library(janitor)

Attaching package: ‘janitor’

The following objects are masked from ‘package:stats’:

    chisq.test, fisher.test
library(readODS)
library(httr)
library(here)
here() starts at /Users/tomdavie/Documents/GitHub/ev_climate_change_project
library(data.table)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
data.table 1.14.0 using 1 threads (see ?getDTthreads).  Latest news: r-datatable.com
**********
This installation of data.table has not detected OpenMP support. It should still work but in single-threaded mode.
This is a Mac. Please read https://mac.r-project.org/openmp/. Please engage with Apple and ask them for support. Check r-datatable.com for updates, and our Mac instructions here: https://github.com/Rdatatable/data.table/wiki/Installation. After several years of many reports of installation problems on Mac, it's time to gingerly point out that there have been no similar problems on Windows or Linux.
**********
library(sf)
Linking to GEOS 3.8.1, GDAL 3.2.1, PROJ 7.2.1
library(leaflet)
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
library(leaflet.extras)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.5     ✓ purrr   0.3.4
✓ tibble  3.1.3     ✓ dplyr   1.0.7
✓ tidyr   1.1.3     ✓ stringr 1.4.0
✓ readr   2.0.1     ✓ forcats 0.5.1
── Conflicts ───────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::between()   masks data.table::between()
x dplyr::filter()    masks stats::filter()
x dplyr::first()     masks data.table::first()
x dplyr::lag()       masks stats::lag()
x dplyr::last()      masks data.table::last()
x purrr::transpose() masks data.table::transpose()
library(grDevices)
# loading in shape file 
uk_shape_file <- st_read(here("raw_data/LA_shape/Local_Authority_Districts__April_2019__UK_BFE_v2.shp")) %>%
  clean_names() %>% 
  st_simplify(dTolerance = 1000) %>%
  st_transform("+proj=longlat +datum=WGS84") %>% 
  dplyr::select(lad19cd, long, lat, geometry) 
Reading layer `Local_Authority_Districts__April_2019__UK_BFE_v2' from data source 
  `/Users/tomdavie/Documents/GitHub/ev_climate_change_project/raw_data/LA_shape/Local_Authority_Districts__April_2019__UK_BFE_v2.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 382 features and 10 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -116.1928 ymin: 5333.603 xmax: 655989 ymax: 1220302
Projected CRS: OSGB 1936 / British National Grid
# Load in clean Electric Vehicles by Local Authority data
uk_ev <- read_csv(here("clean_data/ev_by_la_clean.csv"))
Rows: 475 Columns: 40
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (40): ons_la_code_apr_2019, region_local_authority_apr_2019_3, x2021_q1, x2020_q4, x2020_q3, x2020_q2, x2020_q1, x2...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Joining uk_ev + shape file 
uk_ev_map <- uk_ev %>% 
  left_join(uk_shape_file, by = c("ons_la_code_apr_2019" = "lad19cd")) %>% 
  drop_na() %>% 
  mutate(across(c(x2021_q1:x2011_q4), as.numeric)) %>% 
  st_as_sf()
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` input `..1`.
ℹ `..1 = across(c(x2021_q1:x2011_q4), as.numeric)`.
ℹ NAs introduced by coercion
# Set colours and bins
pal <- colorBin("Greens", domain = uk_ev_map$x2021_q1, bins = c(0, 500, 1000, 2500, 5000, 10000, 15000))

# Set labels
uk_ev_map_labels <- sprintf(
  "<strong>%s</strong><br/>%g Electric Vehicles",
  uk_ev_map$region_local_authority_apr_2019_3, uk_ev_map$x2021_q1) %>% 
  lapply(htmltools::HTML)
# Geospatial of EV Vehicles in the UK 2021 Q1
uk_ev_map %>% 
  leaflet() %>% 
  setView(lng = -4.2026, lat = 55.8, zoom = 4.7, options = list()) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% 
  addPolygons(fillColor = ~pal(x2021_q1),
    weight = 0.1,
    opacity = 0.9, 
    color = "black",
    fillOpacity = 0.8,
    highlightOptions = highlightOptions(color = "green", weight = 2,
                                        bringToFront = TRUE),
    label = uk_ev_map_labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>% 
  addLegend(pal = pal, values = ~x2021_q1, opacity = 0.7, title = NULL,
            position = "bottomright")
    pal <- colorBin("Greens", domain = uk_ev_map$x2021_q1, bins = c(0, 500, 1000, 2500, 5000, 10000, 15000))
    
    uk_ev_map_labels <- sprintf(
      "<strong>%s</strong><br/>%g Electric Vehicles",
      uk_ev_map$region_local_authority_apr_2019_3, uk_ev_map$x2021_q1) %>% 
      lapply(htmltools::HTML)
# Geospatial of EV Vehicles in the UK 2021 Q1
uk_ev_map %>% 
  leaflet() %>% 
  setView(lng = -4.2026, lat = 55.8, zoom = 4.7, options = list()) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% 
  addPolygons(fillColor = ~pal(x2021_q1),
    weight = 0.1,
    opacity = 0.9, 
    color = "black",
    fillOpacity = 0.8,
    highlightOptions = highlightOptions(color = "green", weight = 2,
                                        bringToFront = TRUE),
    label = uk_ev_map_labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>% 
  addLegend(pal = pal, values = ~x2021_q1, opacity = 0.7, title = NULL,
            position = "bottomright")
# Wrangling to create an EV count over time plot 
uk_ev_longer <- uk_ev %>%
  # Pivot longer to get year and count columns
  pivot_longer(cols = c(x2021_q1:x2011_q4), names_to = c("year"), values_to = "no_of_ev") %>% 
  # Filter so we only have UK as a whole data AND we only want final numbers of the year so Q4 
  filter(region_local_authority_apr_2019_3 == "United Kingdom" & str_detect(year, "q4")) %>% 
  # Simplify to just show year
  mutate(year = case_when(str_detect(year, "2021") ~ "2021",
         str_detect(year, "2020") ~ "2020",
         str_detect(year, "2019") ~ "2019",
         str_detect(year, "2018") ~ "2018",
         str_detect(year, "2017") ~ "2017",
         str_detect(year, "2016") ~ "2016",
         str_detect(year, "2015") ~ "2015",
         str_detect(year, "2014") ~ "2014",
         str_detect(year, "2013") ~ "2013",
         str_detect(year, "2012") ~ "2012",
         str_detect(year, "2011") ~ "2011"),
         year = as.numeric(year),
         no_of_ev = as.numeric(no_of_ev))
uk_ev_longer %>% 
  ggplot() +
  aes(x = year, y = no_of_ev) +
  geom_col(fill = "#08a44c") +
  scale_x_continuous(breaks = c(2011:2020)) +
  scale_y_continuous(breaks = seq(0, 220000, by = 20000), limits = c(0, 220000)) +
  labs(title = "\nNumber of Electric Vehicles over time in the UK\n",
       x = "\nYear\n",
       y = "\nNumber of Electric Vehicles\n") +
  theme_minimal() 

Row binding grid NO2 data

no2_2010 <- read_csv(here("raw_data/no2_by_grid_2010.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
Rows: 281802 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_2011 <- read_csv(here("raw_data/no2_by_grid_2011.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
Rows: 281802 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_2012 <- read_csv(here("raw_data/no2_by_grid_2012.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
Rows: 281802 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_2013 <- read_csv(here("raw_data/no2_by_grid_2013.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
Rows: 281802 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_2014 <- read_csv(here("raw_data/no2_by_grid_2014.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
Rows: 281802 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_2015 <- read_csv(here("raw_data/no2_by_grid_2015.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
Rows: 281802 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_2016 <- read_csv(here("raw_data/no2_by_grid_2016.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
Rows: 281802 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_2017 <- read_csv(here("raw_data/no2_by_grid_2017.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
Rows: 281802 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_2018 <- read_csv(here("raw_data/no2_by_grid_2018.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
Rows: 281802 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_2019 <- read_csv(here("raw_data/no2_by_grid_2019.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2"))
Rows: 281802 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Create empty data frame
no2_all <- data_frame()
Warning: `data_frame()` was deprecated in tibble 1.1.0.
Please use `tibble()` instead.
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.
# For each year, bind rows to one dataset
for (i in 2010:2019) {
  df_name <- paste0("no2_", i)
  df_input <- as.name(df_name)
  
  df <- eval(df_input) %>% 
    mutate(year = i)
  
no2_all <- bind_rows(no2_all, df)
  }
# Remove missing NO2 grid values
no2_clean <- no2_all %>% 
  filter(no2 != "MISSING")
library(proj4)
proj4string <- "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs"

no2_clean_row <- no2_clean %>% 
  rowid_to_column()

# Source data
xy <- no2_clean_row %>% 
  select(x, y, rowid)

# Transformed data
pj <- project(xy, proj4string, inverse=TRUE)
Warning in project(xy, proj4string, inverse = TRUE) :
  more than two dimensions found, using first two
latlon <- data.frame(xy, lat=pj$y, lon=pj$x)
final <-  merge(no2_clean_row, latlon, by.x = "rowid", by.y = "rowid") %>%
  filter(year == 2019) %>% 
  select(lat, lon, no2) 
final <- final %>% 
  mutate(no2 = as.numeric(no2)) 
bins <- 10
pal <- colorBin("Spectral", domain = final$no2, bins = bins, na.color = "transparent", reverse = TRUE)

leaflet() %>%
  addProviderTiles("CartoDB.Positron", options = providerTileOptions(noWrap = TRUE)) %>%
  setView(lng = -4.2026, lat = 55.8, zoom = 4.7, options = list()) %>%
  addHeatmap(data = final,
             lng = ~lon,
             lat = ~lat,
             intensity = ~no2,
             minOpacity = 0.1,
             max = 45,
             radius = 1,
             blur = 1) %>% 
  addLegend(pal = pal, values = final$no2,
                title="Average NO2 Conc in 2019")
no2_annual_mean <- read_ods(here("raw_data/NO2_tables.ods"), sheet = 3, skip = 2) %>% 
  clean_names()
no2_annual_mean_all <- no2_annual_mean %>% 
  filter(site == "All sites") %>% 
  mutate(year = as.numeric(year))
no2_annual_mean_all %>% 
  ggplot() +
  aes(x = year, y = annual_mean_no2concentration_mg_m3) + 
  geom_line() +
  theme_minimal() +
  scale_y_continuous(breaks = seq(0, 65, 5), limits = c(22, 62)) +
  scale_x_continuous(breaks = seq(1997, 2020, 1)) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
  labs(x = "\nYear\n", 
       y = "\nAnnual Mean NO2 Conc mg m3\n",
       title = "\nNO2 over time in the UK\n") +
png("no2_time_uk.png", units="in", width=8, height=5, res=300)
# insert ggplot code
dev.off()
null device 
          1 
library(tidyverse)
library(fable)
Loading required package: fabletools
library(tsibble)

Attaching package: ‘tsibble’

The following object is masked from ‘package:data.table’:

    key

The following objects are masked from ‘package:base’:

    intersect, setdiff, union
library(tsibbledata)
library(ggfortify)
forecast_no2 <- no2_annual_mean_all %>% 
  dplyr::select(year, annual_mean_no2concentration_mg_m3) %>% 
  tsibble(index = year)
autoplot(forecast_no2) 
Plot variable not specified, automatically selected `.vars = annual_mean_no2concentration_mg_m3`

fit <- forecast_no2 %>%
  model(
    arima = ARIMA(annual_mean_no2concentration_mg_m3)
  )
fit
forecast_1 <- fit %>%
  fabletools::forecast(h = "15 years")
forecast_1
forecast_1 %>%
  autoplot(forecast_no2, level = NULL) +
  ggtitle("Forecasts for NO2 Conc over time") +
  xlab("Year") +
  guides(colour = guide_legend(title = "Forecast")) +
    theme_minimal() +
  scale_y_continuous(breaks = seq(0, 65, 5), limits = c(0, 62)) +
  scale_x_continuous(breaks = seq(1997, 2034, 3)) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
  labs(x = "\nYear\n", 
       y = "\nAnnual Mean NO2 Conc mg m3\n",
       title = "\nNO2 over time in the UK\n") +
  scale_y_continuous(limit = c(0, 65)) +
  png("no2_time_forecast.png", units="in", width=8, height=5, res=300)
Scale for 'y' is already present. Adding another scale for 'y', which will replace the existing scale.
Warning: Removed 1 row(s) containing missing values (geom_path).
# insert ggplot code
dev.off()
null device 
          1 
# Now set our training data from 1992 to 2006
train <- forecast_no2 %>%
  filter(year <= 2017)

# run the model on the training set 
fit_train <- train %>%
  model(
    arima = ARIMA(annual_mean_no2concentration_mg_m3)
  )
# forecast from the training set
forecast_test <- fit_train %>% 
  fabletools::forecast(h = "4 years")

# Plot forecasts against actual values
forecast_test %>%
  autoplot(train, level = NULL) +
    autolayer(filter(forecast_no2, year >= 2017), color = "black") +
    ggtitle("Forecasts for NO2 Conc over time") +
    xlab("Year") + ylab("Megalitres") +
    guides(colour=guide_legend(title="Forecast"))
Plot variable not specified, automatically selected `.vars = annual_mean_no2concentration_mg_m3`

# Binding 2014 and 2019
no2_2014 <- read_csv(here("raw_data/no2_by_grid_2014.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2")) %>% 
  add_column(year = "2014")
Rows: 281802 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_2019 <- read_csv(here("raw_data/no2_by_grid_2019.csv"), skip = 6, 
  col_names = c("uk_grid_code", "x", "y", "no2")) %>% 
  add_column(year = "2019")
Rows: 281802 Columns: 4
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): no2
dbl (3): uk_grid_code, x, y

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
no2_difference <- bind_rows(no2_2014, no2_2019)
# Diff in NO2 between 2014 & 2019
no2_difference <- no2_difference %>% 
  filter(no2 != "MISSING") %>% 
  mutate(no2 = as.numeric(no2),
         year = as.numeric(year)) %>% 
  group_by(x, y) %>% 
  pivot_wider(names_from = "year", values_from = "no2") %>% 
  rename("x2014" = "2014",
         "x2019" = "2019") %>% 
  mutate(no2_diff_2014_2019 = x2014 - x2019)  %>% 
#Remove this separation when put in cleaning script
  ungroup() %>% 
#Remove this separation when put in cleaning script
  drop_na() %>% 
#Remove this separation when put in cleaning script
# Changing all negative numbers to zero as these aren't of interest to us
  mutate(no2_diff_2014_2019 = if_else(no2_diff_2014_2019 < 0, 0, no2_diff_2014_2019))
# Converting NO2 diff from x y to lat long
library(proj4)
proj4string <- "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs"

no2_diff_row <- no2_difference %>% 
  rowid_to_column()

# Source data
xy <- no2_diff_row %>% 
  dplyr::select(x, y, rowid)

# Transformed data
pj <- project(xy, proj4string, inverse=TRUE)
Warning in project(xy, proj4string, inverse = TRUE) :
  more than two dimensions found, using first two
latlon <- data.frame(xy, lat=pj$y, lon=pj$x)
no2_diff_final <-  merge(no2_diff_row, latlon, by.x = "rowid", by.y = "rowid") %>%
  dplyr::select(lat, lon, no2_diff_2014_2019) 
# Geospatial of No2 diff 2014 to 2019
bins <- c(0, 5, 10, 15, 20, 25, 30)
pal <- colorBin("Spectral", domain = no2_diff_final$no2_diff_2014_2019, bins = bins, na.color = "transparent", reverse = TRUE)

leaflet() %>%
  addProviderTiles("CartoDB.Positron", options = providerTileOptions(noWrap = TRUE)) %>%
  setView(lng = -4.2026, lat = 55.8, zoom = 4.7, options = list()) %>%
  addHeatmap(data = no2_diff_final,
             lng = ~lon,
             lat = ~lat,
             intensity = ~no2_diff_2014_2019,
             minOpacity = 0.1,
             max = 30,
             radius = 1,
             blur = 2) %>% 
  addLegend(pal = pal, values = no2_diff_final$no2_diff_2014_2019,
                title="Annual Mean NO2 Change between 2014 and 2019")
no2_difference_log <- no2_difference %>% 
  mutate(no2_diff_2014_2019_log = log(no2_diff_2014_2019))
no2_difference_log %>% 
  ggplot() +
  geom_histogram(aes(x = no2_diff_2014_2019_log))
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 35278 rows containing non-finite values (stat_bin).

ev_charging <- read_csv(here("raw_data/electric-vehicle-charging-device-statistics-july-2021/EVCD_02-Table 1.csv"), skip = 6) %>% 
  clean_names() %>% 
  dplyr::select(year, month, total_devices, rapid_devices) %>% 
  filter(rapid_devices != "NA") %>% 
  mutate(total_devices = as.numeric(total_devices),
         other_devices = total_devices - rapid_devices) %>% 
  select(-total_devices) %>% 
  pivot_longer(cols = c(other_devices, rapid_devices), names_to = "charger", values_to = "number_of_chargers") %>% 
  filter(month == "October" | month == "July" & year == "2021") %>% 
  mutate(charger = factor(charger, levels = c("rapid_devices", "other_devices")))
New names:
* `` -> ...5
* `` -> ...6
* `` -> ...7
* `` -> ...8
* `` -> ...9
Rows: 38 Columns: 9
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Year, Month, ...5
lgl (4): ...6, ...7, ...8, ...9

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
ev_charging %>% 
  ggplot() +
  aes(x = year, y = number_of_chargers, fill = charger) +
  geom_col() +
  scale_y_continuous(breaks = seq(0, 30000, 2500)) +
  coord_flip() +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 270, vjust = 0.5, hjust=1)) +
  scale_fill_manual(labels = c("Rapid Charger", "Standard Charger"), values = c("#e41a1c", "#4daf4a")) +
  labs(title = "\nNumber of Electric Vehicle Chargers Growth in the UK\n",
       x = "\nYear\n",
       y = "\nNumber of Chargers\n",
       fill = "Charger Type") +
  png("no_chargers_time_uk.png", units="in", width=8, height=5, res=300)
ev_charging_rapid <- read_csv(here("raw_data/electric-vehicle-charging-device-statistics-july-2021/EVCD_01b-Table 1.csv"), skip = 6) %>% 
  clean_names() %>% 
  select(la_region_code, local_authority_region_name, x6) %>% 
  rename("count_rapid" = x6)
New names:
* `` -> ...4
* `` -> ...6
* `` -> ...8
* `` -> ...10
* `` -> ...12
* ...
Rows: 448 Columns: 32
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (18): LA / Region Code, Local Authority / Region Name, Jul-21, ...4, Apr-21, ...6, Jan-21, ...8, Oct-20, ...10, Jul...
lgl (14): ...19, ...20, ...21, ...22, ...23, ...24, ...25, ...26, ...27, ...28, ...29, ...30, ...31, ...32

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
ev_charging_total <- read_csv(here("raw_data/electric-vehicle-charging-device-statistics-july-2021/EVCD_01a-Table 1.csv"), skip = 6) %>% 
  clean_names() %>% 
  select(la_region_code, local_authority_region_name, x6) %>% 
  rename("count_total" = x6)
New names:
* `` -> ...4
* `` -> ...6
* `` -> ...8
* `` -> ...10
* `` -> ...12
* ...
Rows: 448 Columns: 30
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (18): LA / Region Code, Local Authority / Region Name, Jul-21, ...4, Apr-21, ...6, Jan-21, ...8, Oct-20, ...10, Jul...
lgl (12): ...19, ...20, ...21, ...22, ...23, ...24, ...25, ...26, ...27, ...28, ...29, ...30

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
ev_charging_geo <- inner_join(ev_charging_rapid, ev_charging_total, by = "la_region_code") %>% 
  drop_na() %>% 
  select(la_region_code, local_authority_region_name.x, count_rapid, count_total) %>% 
  filter(str_detect(local_authority_region_name.x, "[a-z][a-z]"), 
         count_rapid != "-") %>% 
  mutate(local_authority_region_name.x = str_remove_all(local_authority_region_name.x, "[(](Met County)[)]"),
         local_authority_region_name.x = str_remove_all(local_authority_region_name.x, "[(]abolished \\w+ \\d+[)]"))
# Joining ev_charging_geo + shape file 
ev_charging_map <- ev_charging_geo %>% 
  inner_join(uk_shape_file, by = c("la_region_code" = "lad19cd")) %>% 
  mutate(across(c(count_rapid:count_total), as.numeric)) %>% 
  st_as_sf()
# Set colours and bins
pal <- colorBin("Reds", domain = ev_charging_map$count_total, bins = 10)

# Set labels
ev_charging_map_labels <- sprintf(
  "<strong>%s</strong><br/>%g Chargers per 100k Population",
  ev_charging_map$local_authority_region_name.x, ev_charging_map$count_total, ev_charging_map$count_rapid) %>% 
  lapply(htmltools::HTML)
# Geospatial of EV Chargers Per 100k people in the UK April 21
ev_charging_map %>% 
  leaflet() %>% 
  setView(lng = -4.2026, lat = 55.8, zoom = 4.7, options = list()) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% 
  addPolygons(fillColor = ~pal(count_total),
    weight = 0.1,
    opacity = 0.9, 
    color = "black",
    fillOpacity = 0.8,
    highlightOptions = highlightOptions(color = "green", weight = 2,
                                        bringToFront = TRUE),
    label = ev_charging_map_labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>% 
  addLegend(pal = pal, values = ~count_total, opacity = 0.7, title = NULL,
            position = "bottomright")
# Set colours and bins
pal <- colorBin("Reds", domain = ev_charging_map$count_rapid, bins = 10)

# Set labels
ev_charging_map_labels <- sprintf(
  "<strong>%s</strong><br/>%g Chargers",
  ev_charging_map$local_authority_region_name.x, ev_charging_map$count_rapid, ev_charging_map$count_total) %>% 
  lapply(htmltools::HTML)
# Geospatial of EV Rapid Chargers per 100k people in the UK April 21
ev_charging_map %>% 
  leaflet() %>% 
  setView(lng = -4.2026, lat = 55.8, zoom = 4.7, options = list()) %>%
  addProviderTiles(providers$CartoDB.Positron) %>% 
  addPolygons(fillColor = ~pal(count_rapid),
    weight = 0.1,
    opacity = 0.9, 
    color = "black",
    fillOpacity = 0.8,
    highlightOptions = highlightOptions(color = "green", weight = 2,
                                        bringToFront = TRUE),
    label = ev_charging_map_labels,
    labelOptions = labelOptions(
      style = list("font-weight" = "normal", padding = "3px 8px"),
      textsize = "15px",
      direction = "auto")) %>% 
  addLegend(pal = pal, values = ~count_rapid, opacity = 0.7, title = NULL,
            position = "bottomright")
uk_ev_map_2021 <- uk_ev_map %>% 
  select(ons_la_code_apr_2019, region_local_authority_apr_2019_3, x2021_q1, geometry)

# filter for desired polygon
highlands <- uk_ev_map_2021 %>% 
  filter(region_local_authority_apr_2019_3 == "Highland") 

# st_join seems less dirty
ev_no2 <- final %>% 
  st_as_sf(coords = c("lon", "lat"), crs = st_crs(highlands)) %>% 
  st_join(uk_ev_map_2021, join = st_intersects, left = FALSE) %>% 
  group_by(region_local_authority_apr_2019_3) %>% 
  mutate(mean_no2 = sum(no2))
ev_no2 %>% 
  ggplot() +
  aes(x = x2021_q1, y = mean_no2) +
  geom_point() +
  geom_smooth(se = TRUE)
`geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'

population <- read_csv(here("raw_data/ukpopestimatesmid2020on2021geography/MYE2 - Persons-Table 1.csv"), skip = 7) %>% 
  clean_names() %>% 
  select(code, name, all_ages) %>% 
  mutate(pop_per_100k = all_ages/100000)
New names:
* `` -> ...96
* `` -> ...97
* `` -> ...98
* `` -> ...99
* `` -> ...100
Rows: 420 Columns: 100
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Code, Name, Geography
lgl (5): ...96, ...97, ...98, ...99, ...100

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
ev_no2_tbl <- tibble(ev_no2) %>% 
  select(-c(no2, geometry)) %>% 
  unique()
ev_pop_100k <- ev_no2_tbl %>% 
  left_join(population, by = c("ons_la_code_apr_2019" = "code")) %>% 
  mutate(ev_per_100k = x2021_q1/pop_per_100k) %>% 
  drop_na()
ev_pop_100k_log <- ev_pop_100k %>% 
  mutate(ev_per_100k_log = log(ev_per_100k),
         mean_no2_log = log(mean_no2))
ev_pop_100k_log %>% 
  ggplot() +
  aes(x = ev_per_100k_log, y = mean_no2_log) +
  geom_point() +
  geom_smooth(se = FALSE, method = lm, colour = "#08a44c") +
  theme_minimal() +
  labs(title = "\nElectric Vehicles vs Mean NO2 Conc for each UK Local Authority in 2019\n",
       x = "\nElectric Vehicle per 100k population (log)\n",
       y = "\nMean NO2 Conc (log)\n") +
  png("ev_no2_log.png", units="in", width=8, height=5, res=300)
`geom_smooth()` using formula 'y ~ x'
library(cluster)
library(factoextra)
Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
ev_scale <- ev_pop_100k_log %>% 
  select(region_local_authority_apr_2019_3, x2021_q1, mean_no2) %>% 
  mutate_if(is.numeric, scale)
ev_pop_100k_scale_log <- ev_pop_100k_log %>% 
  select(region_local_authority_apr_2019_3, ev_per_100k, mean_no2) %>% 
  mutate_if(is.numeric, scale)
ev_scale_log %>% 
  ggplot() +
  aes(x = x2021_q1, y = mean_no2) +
  geom_point() +
  geom_smooth(method = lm)
Error in ggplot(.) : object 'ev_scale_log' not found
ev_pop_100k_scale_log %>% 
  ggplot() +
  aes(x = ev_per_100k, y = mean_no2) +
  geom_point() +
  geom_smooth(method = lm)
`geom_smooth()` using formula 'y ~ x'

library(corrplot)
corrplot 0.90 loaded
ev_pop_100k_scale_numeric <- ev_pop_100k_scale %>% 
  select(-region_local_authority_apr_2019_3)
corrplot(cor(ev_pop_100k_scale_numeric), method = "number", type = "lower")

car_by_fuel_gb <- read_ods(here("raw_data/car_by_fuel_by_year_ALL_UK.ods"), skip = 7) %>% 
  clean_names() %>% 
  head(58) %>% 
  mutate(across(c(petrol:zero_emission8), as.numeric)) %>% 
  filter(petrol >= 100) %>% 
  mutate(traditional_fuel = total - alternative_fuels7 - zero_emission8) %>% 
  select(c("year", "petrol", "diesel", "alternative_fuels7", "zero_emission8")) %>% 
  pivot_longer(cols = c(petrol:zero_emission8), names_to = c("fuel_type"), values_to = c("count"))
car_by_fuel_gb %>% 
  ggplot() +
  aes(x = year, y = count, colour = fuel_type) +
  geom_smooth(method = lm) +
  geom_point() 
`geom_smooth()` using formula 'y ~ x'

new_car_by_fuel_gb <- read_ods(here("raw_data/new_car_by_fuel.ods"), skip = 7) %>% 
  clean_names() %>% 
  head(21) %>% 
  mutate(across(c(petrol:zero_emission8), as.numeric)) %>% 
  filter(petrol >= 100) %>% 
  mutate(traditional_fuel = total - alternative_fuels7 - zero_emission8) %>% 
  select(c("date", "petrol", "diesel", "alternative_fuels7", "zero_emission8")) %>% 
  pivot_longer(cols = c(petrol:zero_emission8), names_to = c("fuel_type"), values_to = c("count")) %>% 
  mutate(date = as.numeric(date))
new_car_by_fuel_gb %>% 
  ggplot() +
  aes(x = date, y = count, colour = fuel_type) +
  geom_line(aes(group = fuel_type), size = 1.25) +
  theme_minimal() +
  scale_y_continuous(breaks = seq(0, 2250, 250)) +
  scale_x_continuous(limits = c(2001, 2021), breaks = seq(2001, 2020, 1)) + 
  labs(title = "\nNew Car Registrations by Fuel Type\n",
       x = "\nYear\n",
       y = "\nNumber of Cars ('000s)\n",
       colour = "Fuel Type") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
  panel.grid.minor = element_blank()) +
  scale_colour_manual(labels = c("Alternative Fuels", "Diesel", "Petrol", "Zero Emission"), values = c("#abdda4", "#d7191c", "#fdae61", "#2b83ba")) +
  theme(legend.position = "none")  +
  annotate("text", x = 2006, y = 1750, label = "Petrol", colour = "#fdae61", fontface = 2) +
  annotate("text", x = 2005, y = 1100, label = "Diesel", colour = "#d7191c", fontface = 2) +
  annotate("text", x = 2016, y = 300, label = "Alternative Fuels", colour = "#abdda4", fontface = 2) +
  annotate("text", x = 2008, y = 150, label = "Zero Emissions", colour = "#2b83ba", fontface = 2) +
annotate("text", x = 2020.60, y = 950, label = "987", colour = "#fdae61", fontface = 2) +
  annotate("text", x = 2020.60, y = 250, label = "295", colour = "#d7191c", fontface = 2) +
  annotate("text", x = 2020.60, y = 450, label = "338", colour = "#abdda4", fontface = 2) +
  annotate("text", x = 2020.60, y = 50, label = "106", colour = "#2b83ba", fontface = 2) + 
png("test.png", units="in", width=7, height=5, res=300)
# insert ggplot code
dev.off()
null device 
          1 
uk_ev_top <- uk_ev_top %>% 
  left_join(uk_shape_file, by = c("ons_la_code_apr_2019" = "lad19cd")) %>% 
  drop_na() %>% 
  st_as_sf()
# Converting NO2 diff from x y to lat long
library(proj4)
proj4string <- "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs"

no2_all_clean <- no2_clean %>% 
  rowid_to_column()

# Source data
xy <- no2_all_clean %>% 
  dplyr::select(x, y, rowid)

# Transformed data
pj <- project(xy, proj4string, inverse=TRUE)
Warning in project(xy, proj4string, inverse = TRUE) :
  more than two dimensions found, using first two
latlon <- data.frame(xy, lat=pj$y, lon=pj$x)
no2_all_final <-  merge(no2_all_clean, latlon, by.x = "rowid", by.y = "rowid") %>%
  dplyr::select(lat, lon, no2, year) 
uk_ev_top_2021 <- uk_ev_top %>% 
  select(ons_la_code_apr_2019, region_local_authority_apr_2019_3, year, no_of_ev)

# filter for desired polygon
#highlands <- uk_ev_stockport %>% 
 # filter(region_local_authority_apr_2019_3 == "Highland") 

# st_join seems less dirty
ev_no2_all_years <- no2_all_final %>% 
  st_as_sf(coords = c("lon", "lat"), crs = st_crs(uk_ev_top_2021)) %>%
  st_join(uk_ev_top_2021, join = st_intersects, left = FALSE) 
ev_no2_all_year_top <- tibble(ev_no2_all_years) %>% 
  filter(year.x == year.y) %>% 
  mutate(no2 = as.numeric(no2)) %>% 
  group_by(region_local_authority_apr_2019_3, year.x) %>% 
  mutate(mean_no2 = mean(no2))
ev_no2_all_year_top %>% 
  ggplot() +
  geom_line(aes(x = year.x, y = no_of_ev, colour = region_local_authority_apr_2019_3)) +
  scale_x_continuous(breaks = c(2011:2019)) +
  scale_y_continuous(breaks = seq(0, 2750, 250)) +
  labs(title = "High EV Local Authority over Years",
       x = "Year",
       y = "Number of Electric Vehicles",
       colour = "Local Authority") +
  theme_minimal()

ev_no2_all_year_top %>% 
  ggplot() +
  geom_line(aes(x = year.x, y = mean_no2, colour = region_local_authority_apr_2019_3)) +
  scale_x_continuous(breaks = c(2011:2019)) +
  scale_y_continuous(breaks = c(10:28)) +
  labs(title = "Mean NO2 per Year by Local Authority",
       x = "Year",
       y = "Mean NO2",
       colour = "Local Authority") +
  theme_minimal()

ev_charging_no2_log <- ev_charging_no2 %>% 
  mutate(count_rapid_log = log(count_rapid),
         count_total_log = log(count_total),
         mean_no2_log = log(mean_no2))
ev_charging_no2 %>% 
  ggplot() +
  aes(x = count_rapid, y = mean_no2) +
  geom_point() +
  geom_smooth(se = TRUE, method = lm)
`geom_smooth()` using formula 'y ~ x'

ev_charging_no2 %>% 
  ggplot() +
  aes(x = count_total, y = mean_no2) +
  geom_point() +
  geom_smooth(se = TRUE, method = lm)
`geom_smooth()` using formula 'y ~ x'

ev_charging_no2_log %>% 
  ggplot() +
  aes(x = count_rapid_log, y = mean_no2_log) +
  geom_point() +
  geom_smooth(se = TRUE, method = lm)
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 3772 rows containing non-finite values (stat_smooth).

ev_charging_no2_log %>% 
  ggplot() +
  aes(x = count_total_log, y = mean_no2_log) +
  geom_point() +
  geom_smooth(se = TRUE, method = lm, colour = "#08a44c") +
  theme_minimal() +
  labs(title = "\nEV Chargers vs Mean NO2 Conc for each UK Local Authority in 2019\n",
       x = "\nTotal Number of EV Chargers (log)\n",
       y = "\nMean NO2 Conc (log)\n") +
  png("ev_charger_no2_log.png", units="in", width=8, height=5, res=300)
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 18 rows containing non-finite values (stat_smooth).
uk_ev_income %>% 
  ggplot() +
  aes(x = x2021_q1_log, y = mean_total_annual_income) +
  geom_point() +
  geom_smooth(method = lm, colour = "#08a44c", se = FALSE) +
  theme_minimal() +
  labs(title = "\nEVs vs Mean Annual Income for Local Authorities in England and Wales\n",
       x = "\nNumber of Electric Vehicles (log)\n",
       y = "\nMean Total Annual Income\n") +
  png("ev_income.png", units="in", width=8, height=5, res=300)
`geom_smooth()` using formula 'y ~ x'
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkoamFuaXRvcikKbGlicmFyeShyZWFkT0RTKQpsaWJyYXJ5KGh0dHIpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGxlYWZsZXQpCmxpYnJhcnkobGVhZmxldC5leHRyYXMpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdyRGV2aWNlcykKYGBgCgpgYGB7cn0KIyBsb2FkaW5nIGluIHNoYXBlIGZpbGUgCnVrX3NoYXBlX2ZpbGUgPC0gc3RfcmVhZChoZXJlKCJyYXdfZGF0YS9MQV9zaGFwZS9Mb2NhbF9BdXRob3JpdHlfRGlzdHJpY3RzX19BcHJpbF8yMDE5X19VS19CRkVfdjIuc2hwIikpICU+JQogIGNsZWFuX25hbWVzKCkgJT4lIAogIHN0X3NpbXBsaWZ5KGRUb2xlcmFuY2UgPSAxMDAwKSAlPiUKICBzdF90cmFuc2Zvcm0oIitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0IikgJT4lIAogIGRwbHlyOjpzZWxlY3QobGFkMTljZCwgbG9uZywgbGF0LCBnZW9tZXRyeSkgCmBgYAoKYGBge3J9CiMgTG9hZCBpbiBjbGVhbiBFbGVjdHJpYyBWZWhpY2xlcyBieSBMb2NhbCBBdXRob3JpdHkgZGF0YQp1a19ldiA8LSByZWFkX2NzdihoZXJlKCJjbGVhbl9kYXRhL2V2X2J5X2xhX2NsZWFuLmNzdiIpKQojIEpvaW5pbmcgdWtfZXYgKyBzaGFwZSBmaWxlIAp1a19ldl9tYXAgPC0gdWtfZXYgJT4lIAogIGxlZnRfam9pbih1a19zaGFwZV9maWxlLCBieSA9IGMoIm9uc19sYV9jb2RlX2Fwcl8yMDE5IiA9ICJsYWQxOWNkIikpICU+JSAKICBkcm9wX25hKCkgJT4lIAogIG11dGF0ZShhY3Jvc3MoYyh4MjAyMV9xMTp4MjAxMV9xNCksIGFzLm51bWVyaWMpKSAlPiUgCiAgc3RfYXNfc2YoKQpgYGAKCmBgYHtyfQojIFNldCBjb2xvdXJzIGFuZCBiaW5zCnBhbCA8LSBjb2xvckJpbigiR3JlZW5zIiwgZG9tYWluID0gdWtfZXZfbWFwJHgyMDIxX3ExLCBiaW5zID0gYygwLCA1MDAsIDEwMDAsIDI1MDAsIDUwMDAsIDEwMDAwLCAxNTAwMCkpCgojIFNldCBsYWJlbHMKdWtfZXZfbWFwX2xhYmVscyA8LSBzcHJpbnRmKAogICI8c3Ryb25nPiVzPC9zdHJvbmc+PGJyLz4lZyBFbGVjdHJpYyBWZWhpY2xlcyIsCiAgdWtfZXZfbWFwJHJlZ2lvbl9sb2NhbF9hdXRob3JpdHlfYXByXzIwMTlfMywgdWtfZXZfbWFwJHgyMDIxX3ExKSAlPiUgCiAgbGFwcGx5KGh0bWx0b29sczo6SFRNTCkKYGBgCgpgYGB7cn0KIyBHZW9zcGF0aWFsIG9mIEVWIFZlaGljbGVzIGluIHRoZSBVSyAyMDIxIFExCnVrX2V2X21hcCAlPiUgCiAgbGVhZmxldCgpICU+JSAKICBzZXRWaWV3KGxuZyA9IC00LjIwMjYsIGxhdCA9IDU1LjgsIHpvb20gPSA0LjcsIG9wdGlvbnMgPSBsaXN0KCkpICU+JQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JSAKICBhZGRQb2x5Z29ucyhmaWxsQ29sb3IgPSB+cGFsKHgyMDIxX3ExKSwKICAgIHdlaWdodCA9IDAuMSwKICAgIG9wYWNpdHkgPSAwLjksIAogICAgY29sb3IgPSAiYmxhY2siLAogICAgZmlsbE9wYWNpdHkgPSAwLjgsCiAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJncmVlbiIsIHdlaWdodCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSwKICAgIGxhYmVsID0gdWtfZXZfbWFwX2xhYmVscywKICAgIGxhYmVsT3B0aW9ucyA9IGxhYmVsT3B0aW9ucygKICAgICAgc3R5bGUgPSBsaXN0KCJmb250LXdlaWdodCIgPSAibm9ybWFsIiwgcGFkZGluZyA9ICIzcHggOHB4IiksCiAgICAgIHRleHRzaXplID0gIjE1cHgiLAogICAgICBkaXJlY3Rpb24gPSAiYXV0byIpKSAlPiUgCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gfngyMDIxX3ExLCBvcGFjaXR5ID0gMC43LCB0aXRsZSA9IE5VTEwsCiAgICAgICAgICAgIHBvc2l0aW9uID0gImJvdHRvbXJpZ2h0IikKYGBgCgpgYGB7cn0KICAgIHBhbCA8LSBjb2xvckJpbigiR3JlZW5zIiwgZG9tYWluID0gdWtfZXZfbWFwJHgyMDIxX3ExLCBiaW5zID0gYygwLCA1MDAsIDEwMDAsIDI1MDAsIDUwMDAsIDEwMDAwLCAxNTAwMCkpCiAgICAKICAgIHVrX2V2X21hcF9sYWJlbHMgPC0gc3ByaW50ZigKICAgICAgIjxzdHJvbmc+JXM8L3N0cm9uZz48YnIvPiVnIEVsZWN0cmljIFZlaGljbGVzIiwKICAgICAgdWtfZXZfbWFwJHJlZ2lvbl9sb2NhbF9hdXRob3JpdHlfYXByXzIwMTlfMywgdWtfZXZfbWFwJHgyMDIxX3ExKSAlPiUgCiAgICAgIGxhcHBseShodG1sdG9vbHM6OkhUTUwpCmBgYAoKYGBge3J9CiMgR2Vvc3BhdGlhbCBvZiBFViBWZWhpY2xlcyBpbiB0aGUgVUsgMjAyMSBRMQp1a19ldl9tYXAgJT4lIAogIGxlYWZsZXQoKSAlPiUgCiAgc2V0VmlldyhsbmcgPSAtNC4yMDI2LCBsYXQgPSA1NS44LCB6b29tID0gNC43LCBvcHRpb25zID0gbGlzdCgpKSAlPiUKICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSAlPiUgCiAgYWRkUG9seWdvbnMoZmlsbENvbG9yID0gfnBhbCh4MjAyMV9xMSksCiAgICB3ZWlnaHQgPSAwLjEsCiAgICBvcGFjaXR5ID0gMC45LCAKICAgIGNvbG9yID0gImJsYWNrIiwKICAgIGZpbGxPcGFjaXR5ID0gMC44LAogICAgaGlnaGxpZ2h0T3B0aW9ucyA9IGhpZ2hsaWdodE9wdGlvbnMoY29sb3IgPSAiZ3JlZW4iLCB3ZWlnaHQgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSksCiAgICBsYWJlbCA9IHVrX2V2X21hcF9sYWJlbHMsCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMoCiAgICAgIHN0eWxlID0gbGlzdCgiZm9udC13ZWlnaHQiID0gIm5vcm1hbCIsIHBhZGRpbmcgPSAiM3B4IDhweCIpLAogICAgICB0ZXh0c2l6ZSA9ICIxNXB4IiwKICAgICAgZGlyZWN0aW9uID0gImF1dG8iKSkgJT4lIAogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IH54MjAyMV9xMSwgb3BhY2l0eSA9IDAuNywgdGl0bGUgPSBOVUxMLAogICAgICAgICAgICBwb3NpdGlvbiA9ICJib3R0b21yaWdodCIpCmBgYAogIApgYGB7cn0KIyBXcmFuZ2xpbmcgdG8gY3JlYXRlIGFuIEVWIGNvdW50IG92ZXIgdGltZSBwbG90IAp1a19ldl9sb25nZXIgPC0gdWtfZXYgJT4lCiAgIyBQaXZvdCBsb25nZXIgdG8gZ2V0IHllYXIgYW5kIGNvdW50IGNvbHVtbnMKICBwaXZvdF9sb25nZXIoY29scyA9IGMoeDIwMjFfcTE6eDIwMTFfcTQpLCBuYW1lc190byA9IGMoInllYXIiKSwgdmFsdWVzX3RvID0gIm5vX29mX2V2IikgJT4lIAogICMgRmlsdGVyIHNvIHdlIG9ubHkgaGF2ZSBVSyBhcyBhIHdob2xlIGRhdGEgQU5EIHdlIG9ubHkgd2FudCBmaW5hbCBudW1iZXJzIG9mIHRoZSB5ZWFyIHNvIFE0IAogIGZpbHRlcihyZWdpb25fbG9jYWxfYXV0aG9yaXR5X2Fwcl8yMDE5XzMgPT0gIlVuaXRlZCBLaW5nZG9tIiAmIHN0cl9kZXRlY3QoeWVhciwgInE0IikpICU+JSAKICAjIFNpbXBsaWZ5IHRvIGp1c3Qgc2hvdyB5ZWFyCiAgbXV0YXRlKHllYXIgPSBjYXNlX3doZW4oc3RyX2RldGVjdCh5ZWFyLCAiMjAyMSIpIH4gIjIwMjEiLAogICAgICAgICBzdHJfZGV0ZWN0KHllYXIsICIyMDIwIikgfiAiMjAyMCIsCiAgICAgICAgIHN0cl9kZXRlY3QoeWVhciwgIjIwMTkiKSB+ICIyMDE5IiwKICAgICAgICAgc3RyX2RldGVjdCh5ZWFyLCAiMjAxOCIpIH4gIjIwMTgiLAogICAgICAgICBzdHJfZGV0ZWN0KHllYXIsICIyMDE3IikgfiAiMjAxNyIsCiAgICAgICAgIHN0cl9kZXRlY3QoeWVhciwgIjIwMTYiKSB+ICIyMDE2IiwKICAgICAgICAgc3RyX2RldGVjdCh5ZWFyLCAiMjAxNSIpIH4gIjIwMTUiLAogICAgICAgICBzdHJfZGV0ZWN0KHllYXIsICIyMDE0IikgfiAiMjAxNCIsCiAgICAgICAgIHN0cl9kZXRlY3QoeWVhciwgIjIwMTMiKSB+ICIyMDEzIiwKICAgICAgICAgc3RyX2RldGVjdCh5ZWFyLCAiMjAxMiIpIH4gIjIwMTIiLAogICAgICAgICBzdHJfZGV0ZWN0KHllYXIsICIyMDExIikgfiAiMjAxMSIpLAogICAgICAgICB5ZWFyID0gYXMubnVtZXJpYyh5ZWFyKSwKICAgICAgICAgbm9fb2ZfZXYgPSBhcy5udW1lcmljKG5vX29mX2V2KSkKYGBgCgoKYGBge3J9CnVrX2V2X2xvbmdlciAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0geWVhciwgeSA9IG5vX29mX2V2KSArCiAgZ2VvbV9jb2woZmlsbCA9ICIjMDhhNDRjIikgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKDIwMTE6MjAyMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDIyMDAwMCwgYnkgPSAyMDAwMCksIGxpbWl0cyA9IGMoMCwgMjIwMDAwKSkgKwogIGxhYnModGl0bGUgPSAiXG5OdW1iZXIgb2YgRWxlY3RyaWMgVmVoaWNsZXMgb3ZlciB0aW1lIGluIHRoZSBVS1xuIiwKICAgICAgIHggPSAiXG5ZZWFyXG4iLAogICAgICAgeSA9ICJcbk51bWJlciBvZiBFbGVjdHJpYyBWZWhpY2xlc1xuIikgKwogIHRoZW1lX21pbmltYWwoKSAKYGBgCgogIAoKCiMgUm93IGJpbmRpbmcgZ3JpZCBOTzIgZGF0YSAKCmBgYHtyfQpubzJfMjAxMCA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9ubzJfYnlfZ3JpZF8yMDEwLmNzdiIpLCBza2lwID0gNiwgCiAgY29sX25hbWVzID0gYygidWtfZ3JpZF9jb2RlIiwgIngiLCAieSIsICJubzIiKSkKbm8yXzIwMTEgPC0gcmVhZF9jc3YoaGVyZSgicmF3X2RhdGEvbm8yX2J5X2dyaWRfMjAxMS5jc3YiKSwgc2tpcCA9IDYsIAogIGNvbF9uYW1lcyA9IGMoInVrX2dyaWRfY29kZSIsICJ4IiwgInkiLCAibm8yIikpCm5vMl8yMDEyIDwtIHJlYWRfY3N2KGhlcmUoInJhd19kYXRhL25vMl9ieV9ncmlkXzIwMTIuY3N2IiksIHNraXAgPSA2LCAKICBjb2xfbmFtZXMgPSBjKCJ1a19ncmlkX2NvZGUiLCAieCIsICJ5IiwgIm5vMiIpKQpubzJfMjAxMyA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9ubzJfYnlfZ3JpZF8yMDEzLmNzdiIpLCBza2lwID0gNiwgCiAgY29sX25hbWVzID0gYygidWtfZ3JpZF9jb2RlIiwgIngiLCAieSIsICJubzIiKSkKbm8yXzIwMTQgPC0gcmVhZF9jc3YoaGVyZSgicmF3X2RhdGEvbm8yX2J5X2dyaWRfMjAxNC5jc3YiKSwgc2tpcCA9IDYsIAogIGNvbF9uYW1lcyA9IGMoInVrX2dyaWRfY29kZSIsICJ4IiwgInkiLCAibm8yIikpCm5vMl8yMDE1IDwtIHJlYWRfY3N2KGhlcmUoInJhd19kYXRhL25vMl9ieV9ncmlkXzIwMTUuY3N2IiksIHNraXAgPSA2LCAKICBjb2xfbmFtZXMgPSBjKCJ1a19ncmlkX2NvZGUiLCAieCIsICJ5IiwgIm5vMiIpKQpubzJfMjAxNiA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9ubzJfYnlfZ3JpZF8yMDE2LmNzdiIpLCBza2lwID0gNiwgCiAgY29sX25hbWVzID0gYygidWtfZ3JpZF9jb2RlIiwgIngiLCAieSIsICJubzIiKSkKbm8yXzIwMTcgPC0gcmVhZF9jc3YoaGVyZSgicmF3X2RhdGEvbm8yX2J5X2dyaWRfMjAxNy5jc3YiKSwgc2tpcCA9IDYsIAogIGNvbF9uYW1lcyA9IGMoInVrX2dyaWRfY29kZSIsICJ4IiwgInkiLCAibm8yIikpCm5vMl8yMDE4IDwtIHJlYWRfY3N2KGhlcmUoInJhd19kYXRhL25vMl9ieV9ncmlkXzIwMTguY3N2IiksIHNraXAgPSA2LCAKICBjb2xfbmFtZXMgPSBjKCJ1a19ncmlkX2NvZGUiLCAieCIsICJ5IiwgIm5vMiIpKQpubzJfMjAxOSA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9ubzJfYnlfZ3JpZF8yMDE5LmNzdiIpLCBza2lwID0gNiwgCiAgY29sX25hbWVzID0gYygidWtfZ3JpZF9jb2RlIiwgIngiLCAieSIsICJubzIiKSkKCiMgQ3JlYXRlIGVtcHR5IGRhdGEgZnJhbWUKbm8yX2FsbCA8LSBkYXRhX2ZyYW1lKCkKCiMgRm9yIGVhY2ggeWVhciwgYmluZCByb3dzIHRvIG9uZSBkYXRhc2V0CmZvciAoaSBpbiAyMDEwOjIwMTkpIHsKICBkZl9uYW1lIDwtIHBhc3RlMCgibm8yXyIsIGkpCiAgZGZfaW5wdXQgPC0gYXMubmFtZShkZl9uYW1lKQogIAogIGRmIDwtIGV2YWwoZGZfaW5wdXQpICU+JSAKICAgIG11dGF0ZSh5ZWFyID0gaSkKICAKbm8yX2FsbCA8LSBiaW5kX3Jvd3Mobm8yX2FsbCwgZGYpCiAgfQpgYGAKCmBgYHtyfQojIFJlbW92ZSBtaXNzaW5nIE5PMiBncmlkIHZhbHVlcwpubzJfY2xlYW4gPC0gbm8yX2FsbCAlPiUgCiAgZmlsdGVyKG5vMiAhPSAiTUlTU0lORyIpCmBgYAoKYGBge3J9CmxpYnJhcnkocHJvajQpCnByb2o0c3RyaW5nIDwtICIrcHJvaj10bWVyYyArbGF0XzA9NDkgK2xvbl8wPS0yICtrPTAuOTk5NjAxMjcxNyAreF8wPTQwMDAwMCAreV8wPS0xMDAwMDAgK2VsbHBzPWFpcnkgK2RhdHVtPU9TR0IzNiArdW5pdHM9bSArbm9fZGVmcyIKCm5vMl9jbGVhbl9yb3cgPC0gbm8yX2NsZWFuICU+JSAKICByb3dpZF90b19jb2x1bW4oKQoKIyBTb3VyY2UgZGF0YQp4eSA8LSBubzJfY2xlYW5fcm93ICU+JSAKICBzZWxlY3QoeCwgeSwgcm93aWQpCgojIFRyYW5zZm9ybWVkIGRhdGEKcGogPC0gcHJvamVjdCh4eSwgcHJvajRzdHJpbmcsIGludmVyc2U9VFJVRSkKbGF0bG9uIDwtIGRhdGEuZnJhbWUoeHksIGxhdD1waiR5LCBsb249cGokeCkKZmluYWwgPC0gIG1lcmdlKG5vMl9jbGVhbl9yb3csIGxhdGxvbiwgYnkueCA9ICJyb3dpZCIsIGJ5LnkgPSAicm93aWQiKSAlPiUKICBmaWx0ZXIoeWVhciA9PSAyMDE5KSAlPiUgCiAgc2VsZWN0KGxhdCwgbG9uLCBubzIpIApgYGAKCmBgYHtyfQpmaW5hbCA8LSBmaW5hbCAlPiUgCiAgbXV0YXRlKG5vMiA9IGFzLm51bWVyaWMobm8yKSkgCmBgYAoKYGBge3J9CmJpbnMgPC0gMTAKcGFsIDwtIGNvbG9yQmluKCJTcGVjdHJhbCIsIGRvbWFpbiA9IGZpbmFsJG5vMiwgYmlucyA9IGJpbnMsIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IiwgcmV2ZXJzZSA9IFRSVUUpCgpsZWFmbGV0KCkgJT4lCiAgYWRkUHJvdmlkZXJUaWxlcygiQ2FydG9EQi5Qb3NpdHJvbiIsIG9wdGlvbnMgPSBwcm92aWRlclRpbGVPcHRpb25zKG5vV3JhcCA9IFRSVUUpKSAlPiUKICBzZXRWaWV3KGxuZyA9IC00LjIwMjYsIGxhdCA9IDU1LjgsIHpvb20gPSA0LjcsIG9wdGlvbnMgPSBsaXN0KCkpICU+JQogIGFkZEhlYXRtYXAoZGF0YSA9IGZpbmFsLAogICAgICAgICAgICAgbG5nID0gfmxvbiwKICAgICAgICAgICAgIGxhdCA9IH5sYXQsCiAgICAgICAgICAgICBpbnRlbnNpdHkgPSB+bm8yLAogICAgICAgICAgICAgbWluT3BhY2l0eSA9IDAuMSwKICAgICAgICAgICAgIG1heCA9IDQ1LAogICAgICAgICAgICAgcmFkaXVzID0gMSwKICAgICAgICAgICAgIGJsdXIgPSAxKSAlPiUgCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gZmluYWwkbm8yLAogICAgICAgICAgICAgICAgdGl0bGU9IkF2ZXJhZ2UgTk8yIENvbmMgaW4gMjAxOSIpCmBgYAoKYGBge3J9Cm5vMl9hbm51YWxfbWVhbiA8LSByZWFkX29kcyhoZXJlKCJyYXdfZGF0YS9OTzJfdGFibGVzLm9kcyIpLCBzaGVldCA9IDMsIHNraXAgPSAyKSAlPiUgCiAgY2xlYW5fbmFtZXMoKQpgYGAKCmBgYHtyfQpubzJfYW5udWFsX21lYW5fYWxsIDwtIG5vMl9hbm51YWxfbWVhbiAlPiUgCiAgZmlsdGVyKHNpdGUgPT0gIkFsbCBzaXRlcyIpICU+JSAKICBtdXRhdGUoeWVhciA9IGFzLm51bWVyaWMoeWVhcikpCmBgYAoKYGBge3J9Cm5vMl9hbm51YWxfbWVhbl9hbGwgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IHllYXIsIHkgPSBhbm51YWxfbWVhbl9ubzJjb25jZW50cmF0aW9uX21nX20zKSArIAogIGdlb21fbGluZSgpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNjUsIDUpLCBsaW1pdHMgPSBjKDIyLCA2MikpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDE5OTcsIDIwMjAsIDEpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSArCiAgbGFicyh4ID0gIlxuWWVhclxuIiwgCiAgICAgICB5ID0gIlxuQW5udWFsIE1lYW4gTk8yIENvbmMgbWcgbTNcbiIsCiAgICAgICB0aXRsZSA9ICJcbk5PMiBvdmVyIHRpbWUgaW4gdGhlIFVLXG4iKSArCnBuZygibm8yX3RpbWVfdWsucG5nIiwgdW5pdHM9ImluIiwgd2lkdGg9OCwgaGVpZ2h0PTUsIHJlcz0zMDApCiMgaW5zZXJ0IGdncGxvdCBjb2RlCmRldi5vZmYoKQpgYGAKCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZmFibGUpCmxpYnJhcnkodHNpYmJsZSkKbGlicmFyeSh0c2liYmxlZGF0YSkKbGlicmFyeShnZ2ZvcnRpZnkpCmBgYAoKYGBge3J9CmZvcmVjYXN0X25vMiA8LSBubzJfYW5udWFsX21lYW5fYWxsICU+JSAKICBkcGx5cjo6c2VsZWN0KHllYXIsIGFubnVhbF9tZWFuX25vMmNvbmNlbnRyYXRpb25fbWdfbTMpICU+JSAKICB0c2liYmxlKGluZGV4ID0geWVhcikKYGBgCgpgYGB7cn0KYXV0b3Bsb3QoZm9yZWNhc3Rfbm8yKSAKYGBgCgpgYGB7cn0KZml0IDwtIGZvcmVjYXN0X25vMiAlPiUKICBtb2RlbCgKICAgIGFyaW1hID0gQVJJTUEoYW5udWFsX21lYW5fbm8yY29uY2VudHJhdGlvbl9tZ19tMykKICApCmZpdApgYGAKCmBgYHtyfQpmb3JlY2FzdF8xIDwtIGZpdCAlPiUKICBmYWJsZXRvb2xzOjpmb3JlY2FzdChoID0gIjE1IHllYXJzIikKZm9yZWNhc3RfMQpgYGAKCmBgYHtyfQpmb3JlY2FzdF8xICU+JQogIGF1dG9wbG90KGZvcmVjYXN0X25vMiwgbGV2ZWwgPSBOVUxMKSArCiAgZ2d0aXRsZSgiRm9yZWNhc3RzIGZvciBOTzIgQ29uYyBvdmVyIHRpbWUiKSArCiAgeGxhYigiWWVhciIpICsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkZvcmVjYXN0IikpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA2NSwgNSksIGxpbWl0cyA9IGMoMCwgNjIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxOTk3LCAyMDM0LCAzKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkgKwogIGxhYnMoeCA9ICJcblllYXJcbiIsIAogICAgICAgeSA9ICJcbkFubnVhbCBNZWFuIE5PMiBDb25jIG1nIG0zXG4iLAogICAgICAgdGl0bGUgPSAiXG5OTzIgb3ZlciB0aW1lIGluIHRoZSBVS1xuIikgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdCA9IGMoMCwgNjUpKSArCiAgcG5nKCJubzJfdGltZV9mb3JlY2FzdC5wbmciLCB1bml0cz0iaW4iLCB3aWR0aD04LCBoZWlnaHQ9NSwgcmVzPTMwMCkKIyBpbnNlcnQgZ2dwbG90IGNvZGUKZGV2Lm9mZigpCmBgYAoKYGBge3J9CiMgTm93IHNldCBvdXIgdHJhaW5pbmcgZGF0YSBmcm9tIDE5OTIgdG8gMjAwNgp0cmFpbiA8LSBmb3JlY2FzdF9ubzIgJT4lCiAgZmlsdGVyKHllYXIgPD0gMjAxNykKCiMgcnVuIHRoZSBtb2RlbCBvbiB0aGUgdHJhaW5pbmcgc2V0IApmaXRfdHJhaW4gPC0gdHJhaW4gJT4lCiAgbW9kZWwoCiAgICBhcmltYSA9IEFSSU1BKGFubnVhbF9tZWFuX25vMmNvbmNlbnRyYXRpb25fbWdfbTMpCiAgKQpgYGAKCmBgYHtyfQojIGZvcmVjYXN0IGZyb20gdGhlIHRyYWluaW5nIHNldApmb3JlY2FzdF90ZXN0IDwtIGZpdF90cmFpbiAlPiUgCiAgZmFibGV0b29sczo6Zm9yZWNhc3QoaCA9ICI0IHllYXJzIikKCiMgUGxvdCBmb3JlY2FzdHMgYWdhaW5zdCBhY3R1YWwgdmFsdWVzCmZvcmVjYXN0X3Rlc3QgJT4lCiAgYXV0b3Bsb3QodHJhaW4sIGxldmVsID0gTlVMTCkgKwogICAgYXV0b2xheWVyKGZpbHRlcihmb3JlY2FzdF9ubzIsIHllYXIgPj0gMjAxNyksIGNvbG9yID0gImJsYWNrIikgKwogICAgZ2d0aXRsZSgiRm9yZWNhc3RzIGZvciBOTzIgQ29uYyBvdmVyIHRpbWUiKSArCiAgICB4bGFiKCJZZWFyIikgKyB5bGFiKCJNZWdhbGl0cmVzIikgKwogICAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQodGl0bGU9IkZvcmVjYXN0IikpCmBgYAoKYGBge3J9CiMgQmluZGluZyAyMDE0IGFuZCAyMDE5Cm5vMl8yMDE0IDwtIHJlYWRfY3N2KGhlcmUoInJhd19kYXRhL25vMl9ieV9ncmlkXzIwMTQuY3N2IiksIHNraXAgPSA2LCAKICBjb2xfbmFtZXMgPSBjKCJ1a19ncmlkX2NvZGUiLCAieCIsICJ5IiwgIm5vMiIpKSAlPiUgCiAgYWRkX2NvbHVtbih5ZWFyID0gIjIwMTQiKQpubzJfMjAxOSA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9ubzJfYnlfZ3JpZF8yMDE5LmNzdiIpLCBza2lwID0gNiwgCiAgY29sX25hbWVzID0gYygidWtfZ3JpZF9jb2RlIiwgIngiLCAieSIsICJubzIiKSkgJT4lIAogIGFkZF9jb2x1bW4oeWVhciA9ICIyMDE5IikKCm5vMl9kaWZmZXJlbmNlIDwtIGJpbmRfcm93cyhubzJfMjAxNCwgbm8yXzIwMTkpCmBgYAoKYGBge3J9CiMgRGlmZiBpbiBOTzIgYmV0d2VlbiAyMDE0ICYgMjAxOQpubzJfZGlmZmVyZW5jZSA8LSBubzJfZGlmZmVyZW5jZSAlPiUgCiAgZmlsdGVyKG5vMiAhPSAiTUlTU0lORyIpICU+JSAKICBtdXRhdGUobm8yID0gYXMubnVtZXJpYyhubzIpLAogICAgICAgICB5ZWFyID0gYXMubnVtZXJpYyh5ZWFyKSkgJT4lIAogIGdyb3VwX2J5KHgsIHkpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gInllYXIiLCB2YWx1ZXNfZnJvbSA9ICJubzIiKSAlPiUgCiAgcmVuYW1lKCJ4MjAxNCIgPSAiMjAxNCIsCiAgICAgICAgICJ4MjAxOSIgPSAiMjAxOSIpICU+JSAKICBtdXRhdGUobm8yX2RpZmZfMjAxNF8yMDE5ID0geDIwMTQgLSB4MjAxOSkgICU+JSAKI1JlbW92ZSB0aGlzIHNlcGFyYXRpb24gd2hlbiBwdXQgaW4gY2xlYW5pbmcgc2NyaXB0CiAgdW5ncm91cCgpICU+JSAKI1JlbW92ZSB0aGlzIHNlcGFyYXRpb24gd2hlbiBwdXQgaW4gY2xlYW5pbmcgc2NyaXB0CiAgZHJvcF9uYSgpICU+JSAKI1JlbW92ZSB0aGlzIHNlcGFyYXRpb24gd2hlbiBwdXQgaW4gY2xlYW5pbmcgc2NyaXB0CiMgQ2hhbmdpbmcgYWxsIG5lZ2F0aXZlIG51bWJlcnMgdG8gemVybyBhcyB0aGVzZSBhcmVuJ3Qgb2YgaW50ZXJlc3QgdG8gdXMKICBtdXRhdGUobm8yX2RpZmZfMjAxNF8yMDE5ID0gaWZfZWxzZShubzJfZGlmZl8yMDE0XzIwMTkgPCAwLCAwLCBubzJfZGlmZl8yMDE0XzIwMTkpKQpgYGAKCmBgYHtyfQojIENvbnZlcnRpbmcgTk8yIGRpZmYgZnJvbSB4IHkgdG8gbGF0IGxvbmcKbGlicmFyeShwcm9qNCkKcHJvajRzdHJpbmcgPC0gIitwcm9qPXRtZXJjICtsYXRfMD00OSArbG9uXzA9LTIgK2s9MC45OTk2MDEyNzE3ICt4XzA9NDAwMDAwICt5XzA9LTEwMDAwMCArZWxscHM9YWlyeSArZGF0dW09T1NHQjM2ICt1bml0cz1tICtub19kZWZzIgoKbm8yX2RpZmZfcm93IDwtIG5vMl9kaWZmZXJlbmNlICU+JSAKICByb3dpZF90b19jb2x1bW4oKQoKIyBTb3VyY2UgZGF0YQp4eSA8LSBubzJfZGlmZl9yb3cgJT4lIAogIGRwbHlyOjpzZWxlY3QoeCwgeSwgcm93aWQpCgojIFRyYW5zZm9ybWVkIGRhdGEKcGogPC0gcHJvamVjdCh4eSwgcHJvajRzdHJpbmcsIGludmVyc2U9VFJVRSkKbGF0bG9uIDwtIGRhdGEuZnJhbWUoeHksIGxhdD1waiR5LCBsb249cGokeCkKbm8yX2RpZmZfZmluYWwgPC0gIG1lcmdlKG5vMl9kaWZmX3JvdywgbGF0bG9uLCBieS54ID0gInJvd2lkIiwgYnkueSA9ICJyb3dpZCIpICU+JQogIGRwbHlyOjpzZWxlY3QobGF0LCBsb24sIG5vMl9kaWZmXzIwMTRfMjAxOSkgCmBgYAoKYGBge3J9CiMgR2Vvc3BhdGlhbCBvZiBObzIgZGlmZiAyMDE0IHRvIDIwMTkKYmlucyA8LSBjKDAsIDUsIDEwLCAxNSwgMjAsIDI1LCAzMCkKcGFsIDwtIGNvbG9yQmluKCJTcGVjdHJhbCIsIGRvbWFpbiA9IG5vMl9kaWZmX2ZpbmFsJG5vMl9kaWZmXzIwMTRfMjAxOSwgYmlucyA9IGJpbnMsIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IiwgcmV2ZXJzZSA9IFRSVUUpCgpsZWFmbGV0KCkgJT4lCiAgYWRkUHJvdmlkZXJUaWxlcygiQ2FydG9EQi5Qb3NpdHJvbiIsIG9wdGlvbnMgPSBwcm92aWRlclRpbGVPcHRpb25zKG5vV3JhcCA9IFRSVUUpKSAlPiUKICBzZXRWaWV3KGxuZyA9IC00LjIwMjYsIGxhdCA9IDU1LjgsIHpvb20gPSA0LjcsIG9wdGlvbnMgPSBsaXN0KCkpICU+JQogIGFkZEhlYXRtYXAoZGF0YSA9IG5vMl9kaWZmX2ZpbmFsLAogICAgICAgICAgICAgbG5nID0gfmxvbiwKICAgICAgICAgICAgIGxhdCA9IH5sYXQsCiAgICAgICAgICAgICBpbnRlbnNpdHkgPSB+bm8yX2RpZmZfMjAxNF8yMDE5LAogICAgICAgICAgICAgbWluT3BhY2l0eSA9IDAuMSwKICAgICAgICAgICAgIG1heCA9IDMwLAogICAgICAgICAgICAgcmFkaXVzID0gMSwKICAgICAgICAgICAgIGJsdXIgPSAyKSAlPiUgCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gbm8yX2RpZmZfZmluYWwkbm8yX2RpZmZfMjAxNF8yMDE5LAogICAgICAgICAgICAgICAgdGl0bGU9IkFubnVhbCBNZWFuIE5PMiBDaGFuZ2UgYmV0d2VlbiAyMDE0IGFuZCAyMDE5IikKYGBgCgpgYGB7cn0Kbm8yX2RpZmZlcmVuY2VfbG9nIDwtIG5vMl9kaWZmZXJlbmNlICU+JSAKICBtdXRhdGUobm8yX2RpZmZfMjAxNF8yMDE5X2xvZyA9IGxvZyhubzJfZGlmZl8yMDE0XzIwMTkpKQpgYGAKCmBgYHtyfQpubzJfZGlmZmVyZW5jZV9sb2cgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IG5vMl9kaWZmXzIwMTRfMjAxOV9sb2cpKQpgYGAKCmBgYHtyfQpldl9jaGFyZ2luZyA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9lbGVjdHJpYy12ZWhpY2xlLWNoYXJnaW5nLWRldmljZS1zdGF0aXN0aWNzLWp1bHktMjAyMS9FVkNEXzAyLVRhYmxlIDEuY3N2IiksIHNraXAgPSA2KSAlPiUgCiAgY2xlYW5fbmFtZXMoKSAlPiUgCiAgZHBseXI6OnNlbGVjdCh5ZWFyLCBtb250aCwgdG90YWxfZGV2aWNlcywgcmFwaWRfZGV2aWNlcykgJT4lIAogIGZpbHRlcihyYXBpZF9kZXZpY2VzICE9ICJOQSIpICU+JSAKICBtdXRhdGUodG90YWxfZGV2aWNlcyA9IGFzLm51bWVyaWModG90YWxfZGV2aWNlcyksCiAgICAgICAgIG90aGVyX2RldmljZXMgPSB0b3RhbF9kZXZpY2VzIC0gcmFwaWRfZGV2aWNlcykgJT4lIAogIHNlbGVjdCgtdG90YWxfZGV2aWNlcykgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gYyhvdGhlcl9kZXZpY2VzLCByYXBpZF9kZXZpY2VzKSwgbmFtZXNfdG8gPSAiY2hhcmdlciIsIHZhbHVlc190byA9ICJudW1iZXJfb2ZfY2hhcmdlcnMiKSAlPiUgCiAgZmlsdGVyKG1vbnRoID09ICJPY3RvYmVyIiB8IG1vbnRoID09ICJKdWx5IiAmIHllYXIgPT0gIjIwMjEiKSAlPiUgCiAgbXV0YXRlKGNoYXJnZXIgPSBmYWN0b3IoY2hhcmdlciwgbGV2ZWxzID0gYygicmFwaWRfZGV2aWNlcyIsICJvdGhlcl9kZXZpY2VzIikpKQpgYGAKCmBgYHtyfQpldl9jaGFyZ2luZyAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0geWVhciwgeSA9IG51bWJlcl9vZl9jaGFyZ2VycywgZmlsbCA9IGNoYXJnZXIpICsKICBnZW9tX2NvbCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDMwMDAwLCAyNTAwKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDI3MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobGFiZWxzID0gYygiUmFwaWQgQ2hhcmdlciIsICJTdGFuZGFyZCBDaGFyZ2VyIiksIHZhbHVlcyA9IGMoIiNlNDFhMWMiLCAiIzRkYWY0YSIpKSArCiAgbGFicyh0aXRsZSA9ICJcbk51bWJlciBvZiBFbGVjdHJpYyBWZWhpY2xlIENoYXJnZXJzIEdyb3d0aCBpbiB0aGUgVUtcbiIsCiAgICAgICB4ID0gIlxuWWVhclxuIiwKICAgICAgIHkgPSAiXG5OdW1iZXIgb2YgQ2hhcmdlcnNcbiIsCiAgICAgICBmaWxsID0gIkNoYXJnZXIgVHlwZSIpICsKICBwbmcoIm5vX2NoYXJnZXJzX3RpbWVfdWsucG5nIiwgdW5pdHM9ImluIiwgd2lkdGg9OCwgaGVpZ2h0PTUsIHJlcz0zMDApCgpgYGAKCmBgYHtyfQpldl9jaGFyZ2luZ19yYXBpZCA8LSByZWFkX2NzdihoZXJlKCJyYXdfZGF0YS9lbGVjdHJpYy12ZWhpY2xlLWNoYXJnaW5nLWRldmljZS1zdGF0aXN0aWNzLWp1bHktMjAyMS9FVkNEXzAxYi1UYWJsZSAxLmNzdiIpLCBza2lwID0gNikgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lIAogIHNlbGVjdChsYV9yZWdpb25fY29kZSwgbG9jYWxfYXV0aG9yaXR5X3JlZ2lvbl9uYW1lLCB4NikgJT4lIAogIHJlbmFtZSgiY291bnRfcmFwaWQiID0geDYpCmV2X2NoYXJnaW5nX3RvdGFsIDwtIHJlYWRfY3N2KGhlcmUoInJhd19kYXRhL2VsZWN0cmljLXZlaGljbGUtY2hhcmdpbmctZGV2aWNlLXN0YXRpc3RpY3MtanVseS0yMDIxL0VWQ0RfMDFhLVRhYmxlIDEuY3N2IiksIHNraXAgPSA2KSAlPiUgCiAgY2xlYW5fbmFtZXMoKSAlPiUgCiAgc2VsZWN0KGxhX3JlZ2lvbl9jb2RlLCBsb2NhbF9hdXRob3JpdHlfcmVnaW9uX25hbWUsIHg2KSAlPiUgCiAgcmVuYW1lKCJjb3VudF90b3RhbCIgPSB4NikKCmV2X2NoYXJnaW5nX2dlbyA8LSBpbm5lcl9qb2luKGV2X2NoYXJnaW5nX3JhcGlkLCBldl9jaGFyZ2luZ190b3RhbCwgYnkgPSAibGFfcmVnaW9uX2NvZGUiKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBzZWxlY3QobGFfcmVnaW9uX2NvZGUsIGxvY2FsX2F1dGhvcml0eV9yZWdpb25fbmFtZS54LCBjb3VudF9yYXBpZCwgY291bnRfdG90YWwpICU+JSAKICBmaWx0ZXIoc3RyX2RldGVjdChsb2NhbF9hdXRob3JpdHlfcmVnaW9uX25hbWUueCwgIlthLXpdW2Etel0iKSwgCiAgICAgICAgIGNvdW50X3JhcGlkICE9ICItIikgJT4lIAogIG11dGF0ZShsb2NhbF9hdXRob3JpdHlfcmVnaW9uX25hbWUueCA9IHN0cl9yZW1vdmVfYWxsKGxvY2FsX2F1dGhvcml0eV9yZWdpb25fbmFtZS54LCAiWyhdKE1ldCBDb3VudHkpWyldIiksCiAgICAgICAgIGxvY2FsX2F1dGhvcml0eV9yZWdpb25fbmFtZS54ID0gc3RyX3JlbW92ZV9hbGwobG9jYWxfYXV0aG9yaXR5X3JlZ2lvbl9uYW1lLngsICJbKF1hYm9saXNoZWQgXFx3KyBcXGQrWyldIikpCmBgYAoKYGBge3J9CiMgSm9pbmluZyBldl9jaGFyZ2luZ19nZW8gKyBzaGFwZSBmaWxlIApldl9jaGFyZ2luZ19tYXAgPC0gZXZfY2hhcmdpbmdfZ2VvICU+JSAKICBpbm5lcl9qb2luKHVrX3NoYXBlX2ZpbGUsIGJ5ID0gYygibGFfcmVnaW9uX2NvZGUiID0gImxhZDE5Y2QiKSkgJT4lIAogIG11dGF0ZShhY3Jvc3MoYyhjb3VudF9yYXBpZDpjb3VudF90b3RhbCksIGFzLm51bWVyaWMpKSAlPiUgCiAgc3RfYXNfc2YoKQpgYGAKCmBgYHtyfQojIFNldCBjb2xvdXJzIGFuZCBiaW5zCnBhbCA8LSBjb2xvckJpbigiUmVkcyIsIGRvbWFpbiA9IGV2X2NoYXJnaW5nX21hcCRjb3VudF90b3RhbCwgYmlucyA9IDEwKQoKIyBTZXQgbGFiZWxzCmV2X2NoYXJnaW5nX21hcF9sYWJlbHMgPC0gc3ByaW50ZigKICAiPHN0cm9uZz4lczwvc3Ryb25nPjxici8+JWcgQ2hhcmdlcnMgcGVyIDEwMGsgUG9wdWxhdGlvbiIsCiAgZXZfY2hhcmdpbmdfbWFwJGxvY2FsX2F1dGhvcml0eV9yZWdpb25fbmFtZS54LCBldl9jaGFyZ2luZ19tYXAkY291bnRfdG90YWwsIGV2X2NoYXJnaW5nX21hcCRjb3VudF9yYXBpZCkgJT4lIAogIGxhcHBseShodG1sdG9vbHM6OkhUTUwpCmBgYAoKYGBge3J9CiMgR2Vvc3BhdGlhbCBvZiBFViBDaGFyZ2VycyBQZXIgMTAwayBwZW9wbGUgaW4gdGhlIFVLIEFwcmlsIDIxCmV2X2NoYXJnaW5nX21hcCAlPiUgCiAgbGVhZmxldCgpICU+JSAKICBzZXRWaWV3KGxuZyA9IC00LjIwMjYsIGxhdCA9IDU1LjgsIHpvb20gPSA0LjcsIG9wdGlvbnMgPSBsaXN0KCkpICU+JQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JSAKICBhZGRQb2x5Z29ucyhmaWxsQ29sb3IgPSB+cGFsKGNvdW50X3RvdGFsKSwKICAgIHdlaWdodCA9IDAuMSwKICAgIG9wYWNpdHkgPSAwLjksIAogICAgY29sb3IgPSAiYmxhY2siLAogICAgZmlsbE9wYWNpdHkgPSAwLjgsCiAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJncmVlbiIsIHdlaWdodCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSwKICAgIGxhYmVsID0gZXZfY2hhcmdpbmdfbWFwX2xhYmVscywKICAgIGxhYmVsT3B0aW9ucyA9IGxhYmVsT3B0aW9ucygKICAgICAgc3R5bGUgPSBsaXN0KCJmb250LXdlaWdodCIgPSAibm9ybWFsIiwgcGFkZGluZyA9ICIzcHggOHB4IiksCiAgICAgIHRleHRzaXplID0gIjE1cHgiLAogICAgICBkaXJlY3Rpb24gPSAiYXV0byIpKSAlPiUgCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gfmNvdW50X3RvdGFsLCBvcGFjaXR5ID0gMC43LCB0aXRsZSA9IE5VTEwsCiAgICAgICAgICAgIHBvc2l0aW9uID0gImJvdHRvbXJpZ2h0IikKYGBgCgoKYGBge3J9CiMgU2V0IGNvbG91cnMgYW5kIGJpbnMKcGFsIDwtIGNvbG9yQmluKCJSZWRzIiwgZG9tYWluID0gZXZfY2hhcmdpbmdfbWFwJGNvdW50X3JhcGlkLCBiaW5zID0gMTApCgojIFNldCBsYWJlbHMKZXZfY2hhcmdpbmdfbWFwX2xhYmVscyA8LSBzcHJpbnRmKAogICI8c3Ryb25nPiVzPC9zdHJvbmc+PGJyLz4lZyBDaGFyZ2VycyIsCiAgZXZfY2hhcmdpbmdfbWFwJGxvY2FsX2F1dGhvcml0eV9yZWdpb25fbmFtZS54LCBldl9jaGFyZ2luZ19tYXAkY291bnRfcmFwaWQsIGV2X2NoYXJnaW5nX21hcCRjb3VudF90b3RhbCkgJT4lIAogIGxhcHBseShodG1sdG9vbHM6OkhUTUwpCmBgYAoKYGBge3J9CiMgR2Vvc3BhdGlhbCBvZiBFViBSYXBpZCBDaGFyZ2VycyBwZXIgMTAwayBwZW9wbGUgaW4gdGhlIFVLIEFwcmlsIDIxCmV2X2NoYXJnaW5nX21hcCAlPiUgCiAgbGVhZmxldCgpICU+JSAKICBzZXRWaWV3KGxuZyA9IC00LjIwMjYsIGxhdCA9IDU1LjgsIHpvb20gPSA0LjcsIG9wdGlvbnMgPSBsaXN0KCkpICU+JQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JSAKICBhZGRQb2x5Z29ucyhmaWxsQ29sb3IgPSB+cGFsKGNvdW50X3JhcGlkKSwKICAgIHdlaWdodCA9IDAuMSwKICAgIG9wYWNpdHkgPSAwLjksIAogICAgY29sb3IgPSAiYmxhY2siLAogICAgZmlsbE9wYWNpdHkgPSAwLjgsCiAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJncmVlbiIsIHdlaWdodCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSwKICAgIGxhYmVsID0gZXZfY2hhcmdpbmdfbWFwX2xhYmVscywKICAgIGxhYmVsT3B0aW9ucyA9IGxhYmVsT3B0aW9ucygKICAgICAgc3R5bGUgPSBsaXN0KCJmb250LXdlaWdodCIgPSAibm9ybWFsIiwgcGFkZGluZyA9ICIzcHggOHB4IiksCiAgICAgIHRleHRzaXplID0gIjE1cHgiLAogICAgICBkaXJlY3Rpb24gPSAiYXV0byIpKSAlPiUgCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gfmNvdW50X3JhcGlkLCBvcGFjaXR5ID0gMC43LCB0aXRsZSA9IE5VTEwsCiAgICAgICAgICAgIHBvc2l0aW9uID0gImJvdHRvbXJpZ2h0IikKYGBgCgpgYGB7cn0KdWtfZXZfbWFwXzIwMjEgPC0gdWtfZXZfbWFwICU+JSAKICBzZWxlY3Qob25zX2xhX2NvZGVfYXByXzIwMTksIHJlZ2lvbl9sb2NhbF9hdXRob3JpdHlfYXByXzIwMTlfMywgeDIwMjFfcTEsIGdlb21ldHJ5KQoKIyBmaWx0ZXIgZm9yIGRlc2lyZWQgcG9seWdvbgpoaWdobGFuZHMgPC0gdWtfZXZfbWFwXzIwMjEgJT4lIAogIGZpbHRlcihyZWdpb25fbG9jYWxfYXV0aG9yaXR5X2Fwcl8yMDE5XzMgPT0gIkhpZ2hsYW5kIikgCgojIHN0X2pvaW4gc2VlbXMgbGVzcyBkaXJ0eQpldl9ubzIgPC0gZmluYWwgJT4lIAogIHN0X2FzX3NmKGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwgY3JzID0gc3RfY3JzKGhpZ2hsYW5kcykpICU+JSAKICBzdF9qb2luKHVrX2V2X21hcF8yMDIxLCBqb2luID0gc3RfaW50ZXJzZWN0cywgbGVmdCA9IEZBTFNFKSAlPiUgCiAgZ3JvdXBfYnkocmVnaW9uX2xvY2FsX2F1dGhvcml0eV9hcHJfMjAxOV8zKSAlPiUgCiAgbXV0YXRlKG1lYW5fbm8yID0gc3VtKG5vMikpCmBgYAoKYGBge3J9CmV2X25vMiAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0geDIwMjFfcTEsIHkgPSBtZWFuX25vMikgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBUUlVFKQpgYGAKCmBgYHtyfQpwb3B1bGF0aW9uIDwtIHJlYWRfY3N2KGhlcmUoInJhd19kYXRhL3VrcG9wZXN0aW1hdGVzbWlkMjAyMG9uMjAyMWdlb2dyYXBoeS9NWUUyIC0gUGVyc29ucy1UYWJsZSAxLmNzdiIpLCBza2lwID0gNykgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lIAogIHNlbGVjdChjb2RlLCBuYW1lLCBhbGxfYWdlcykgJT4lIAogIG11dGF0ZShwb3BfcGVyXzEwMGsgPSBhbGxfYWdlcy8xMDAwMDApCmBgYAoKYGBge3J9CmV2X25vMl90YmwgPC0gdGliYmxlKGV2X25vMikgJT4lIAogIHNlbGVjdCgtYyhubzIsIGdlb21ldHJ5KSkgJT4lIAogIHVuaXF1ZSgpCmBgYAoKYGBge3J9CmV2X3BvcF8xMDBrIDwtIGV2X25vMl90YmwgJT4lIAogIGxlZnRfam9pbihwb3B1bGF0aW9uLCBieSA9IGMoIm9uc19sYV9jb2RlX2Fwcl8yMDE5IiA9ICJjb2RlIikpICU+JSAKICBtdXRhdGUoZXZfcGVyXzEwMGsgPSB4MjAyMV9xMS9wb3BfcGVyXzEwMGspICU+JSAKICBkcm9wX25hKCkKYGBgCgpgYGB7cn0KZXZfcG9wXzEwMGtfbG9nIDwtIGV2X3BvcF8xMDBrICU+JSAKICBtdXRhdGUoZXZfcGVyXzEwMGtfbG9nID0gbG9nKGV2X3Blcl8xMDBrKSwKICAgICAgICAgbWVhbl9ubzJfbG9nID0gbG9nKG1lYW5fbm8yKSkKYGBgCgpgYGB7cn0KZXZfcG9wXzEwMGtfbG9nICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBldl9wZXJfMTAwa19sb2csIHkgPSBtZWFuX25vMl9sb2cpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKHNlID0gRkFMU0UsIG1ldGhvZCA9IGxtLCBjb2xvdXIgPSAiIzA4YTQ0YyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiXG5FbGVjdHJpYyBWZWhpY2xlcyB2cyBNZWFuIE5PMiBDb25jIGZvciBlYWNoIFVLIExvY2FsIEF1dGhvcml0eSBpbiAyMDE5XG4iLAogICAgICAgeCA9ICJcbkVsZWN0cmljIFZlaGljbGUgcGVyIDEwMGsgcG9wdWxhdGlvbiAobG9nKVxuIiwKICAgICAgIHkgPSAiXG5NZWFuIE5PMiBDb25jIChsb2cpXG4iKSArCiAgcG5nKCJldl9ubzJfbG9nLnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD01LCByZXM9MzAwKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGNsdXN0ZXIpCmxpYnJhcnkoZmFjdG9leHRyYSkKYGBgCgpgYGB7cn0KZXZfc2NhbGUgPC0gZXZfcG9wXzEwMGtfbG9nICU+JSAKICBzZWxlY3QocmVnaW9uX2xvY2FsX2F1dGhvcml0eV9hcHJfMjAxOV8zLCB4MjAyMV9xMSwgbWVhbl9ubzIpICU+JSAKICBtdXRhdGVfaWYoaXMubnVtZXJpYywgc2NhbGUpCmBgYAoKYGBge3J9CmV2X3BvcF8xMDBrX3NjYWxlX2xvZyA8LSBldl9wb3BfMTAwa19sb2cgJT4lIAogIHNlbGVjdChyZWdpb25fbG9jYWxfYXV0aG9yaXR5X2Fwcl8yMDE5XzMsIGV2X3Blcl8xMDBrLCBtZWFuX25vMikgJT4lIAogIG11dGF0ZV9pZihpcy5udW1lcmljLCBzY2FsZSkKYGBgCgpgYGB7cn0KZXZfc2NhbGVfbG9nICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSB4MjAyMV9xMSwgeSA9IG1lYW5fbm8yKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSBsbSkKYGBgCgpgYGB7cn0KZXZfcG9wXzEwMGtfc2NhbGVfbG9nICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBldl9wZXJfMTAwaywgeSA9IG1lYW5fbm8yKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSBsbSkKYGBgCgpgYGB7cn0KbGlicmFyeShjb3JycGxvdCkKYGBgCmBgYHtyfQpldl9wb3BfMTAwa19zY2FsZSAlPiUgCiAgYXNfdGliYmxlKCkgJT4lCiAgcGl2b3RfbG9uZ2VyKC1yZWdpb25fbG9jYWxfYXV0aG9yaXR5X2Fwcl8yMDE5XzMsCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInR5cGUiLCAKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgZ3JvdXBfYnkodHlwZSkgJT4lCiAgc3VtbWFyaXNlKG1lYW4gPSByb3VuZChtZWFuKHZhbHVlKSksIAogICAgICAgICAgICBzZCA9IHNkKHZhbHVlKSkKYGBgCmBgYHtyfQpldl9wb3BfMTAwa19zY2FsZV9udW1lcmljIDwtIGV2X3BvcF8xMDBrX3NjYWxlICU+JSAKICBzZWxlY3QoLXJlZ2lvbl9sb2NhbF9hdXRob3JpdHlfYXByXzIwMTlfMykKYGBgCgoKYGBge3J9CmNvcnJwbG90KGNvcihldl9wb3BfMTAwa19zY2FsZV9udW1lcmljKSwgbWV0aG9kID0gIm51bWJlciIsIHR5cGUgPSAibG93ZXIiKQpgYGAKCmBgYHtyfQpjYXJfYnlfZnVlbF9nYiA8LSByZWFkX29kcyhoZXJlKCJyYXdfZGF0YS9jYXJfYnlfZnVlbF9ieV95ZWFyX0FMTF9VSy5vZHMiKSwgc2tpcCA9IDcpICU+JSAKICBjbGVhbl9uYW1lcygpICU+JSAKICBoZWFkKDU4KSAlPiUgCiAgbXV0YXRlKGFjcm9zcyhjKHBldHJvbDp6ZXJvX2VtaXNzaW9uOCksIGFzLm51bWVyaWMpKSAlPiUgCiAgZmlsdGVyKHBldHJvbCA+PSAxMDApICU+JSAKICBtdXRhdGUodHJhZGl0aW9uYWxfZnVlbCA9IHRvdGFsIC0gYWx0ZXJuYXRpdmVfZnVlbHM3IC0gemVyb19lbWlzc2lvbjgpICU+JSAKICBzZWxlY3QoYygieWVhciIsICJwZXRyb2wiLCAiZGllc2VsIiwgImFsdGVybmF0aXZlX2Z1ZWxzNyIsICJ6ZXJvX2VtaXNzaW9uOCIpKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHBldHJvbDp6ZXJvX2VtaXNzaW9uOCksIG5hbWVzX3RvID0gYygiZnVlbF90eXBlIiksIHZhbHVlc190byA9IGMoImNvdW50IikpCmBgYAoKYGBge3J9CmNhcl9ieV9mdWVsX2diICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSB5ZWFyLCB5ID0gY291bnQsIGNvbG91ciA9IGZ1ZWxfdHlwZSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtKSArCiAgZ2VvbV9wb2ludCgpIApgYGAKCmBgYHtyfQpuZXdfY2FyX2J5X2Z1ZWxfZ2IgPC0gcmVhZF9vZHMoaGVyZSgicmF3X2RhdGEvbmV3X2Nhcl9ieV9mdWVsLm9kcyIpLCBza2lwID0gNykgJT4lIAogIGNsZWFuX25hbWVzKCkgJT4lIAogIGhlYWQoMjEpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwZXRyb2w6emVyb19lbWlzc2lvbjgpLCBhcy5udW1lcmljKSkgJT4lIAogIGZpbHRlcihwZXRyb2wgPj0gMTAwKSAlPiUgCiAgbXV0YXRlKHRyYWRpdGlvbmFsX2Z1ZWwgPSB0b3RhbCAtIGFsdGVybmF0aXZlX2Z1ZWxzNyAtIHplcm9fZW1pc3Npb244KSAlPiUgCiAgc2VsZWN0KGMoImRhdGUiLCAicGV0cm9sIiwgImRpZXNlbCIsICJhbHRlcm5hdGl2ZV9mdWVsczciLCAiemVyb19lbWlzc2lvbjgiKSkgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gYyhwZXRyb2w6emVyb19lbWlzc2lvbjgpLCBuYW1lc190byA9IGMoImZ1ZWxfdHlwZSIpLCB2YWx1ZXNfdG8gPSBjKCJjb3VudCIpKSAlPiUgCiAgbXV0YXRlKGRhdGUgPSBhcy5udW1lcmljKGRhdGUpKQpgYGAKCmBgYHtyfQpuZXdfY2FyX2J5X2Z1ZWxfZ2IgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IGRhdGUsIHkgPSBjb3VudCwgY29sb3VyID0gZnVlbF90eXBlKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGZ1ZWxfdHlwZSksIHNpemUgPSAxLjI1KSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDIyNTAsIDI1MCkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygyMDAxLCAyMDIxKSwgYnJlYWtzID0gc2VxKDIwMDEsIDIwMjAsIDEpKSArIAogIGxhYnModGl0bGUgPSAiXG5OZXcgQ2FyIFJlZ2lzdHJhdGlvbnMgYnkgRnVlbCBUeXBlXG4iLAogICAgICAgeCA9ICJcblllYXJcbiIsCiAgICAgICB5ID0gIlxuTnVtYmVyIG9mIENhcnMgKCcwMDBzKVxuIiwKICAgICAgIGNvbG91ciA9ICJGdWVsIFR5cGUiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLAogIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKGxhYmVscyA9IGMoIkFsdGVybmF0aXZlIEZ1ZWxzIiwgIkRpZXNlbCIsICJQZXRyb2wiLCAiWmVybyBFbWlzc2lvbiIpLCB2YWx1ZXMgPSBjKCIjYWJkZGE0IiwgIiNkNzE5MWMiLCAiI2ZkYWU2MSIsICIjMmI4M2JhIikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMjAwNiwgeSA9IDE3NTAsIGxhYmVsID0gIlBldHJvbCIsIGNvbG91ciA9ICIjZmRhZTYxIiwgZm9udGZhY2UgPSAyKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMjAwNSwgeSA9IDExMDAsIGxhYmVsID0gIkRpZXNlbCIsIGNvbG91ciA9ICIjZDcxOTFjIiwgZm9udGZhY2UgPSAyKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMjAxNiwgeSA9IDMwMCwgbGFiZWwgPSAiQWx0ZXJuYXRpdmUgRnVlbHMiLCBjb2xvdXIgPSAiI2FiZGRhNCIsIGZvbnRmYWNlID0gMikgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIwMDgsIHkgPSAxNTAsIGxhYmVsID0gIlplcm8gRW1pc3Npb25zIiwgY29sb3VyID0gIiMyYjgzYmEiLCBmb250ZmFjZSA9IDIpICsKYW5ub3RhdGUoInRleHQiLCB4ID0gMjAyMC42MCwgeSA9IDk1MCwgbGFiZWwgPSAiOTg3IiwgY29sb3VyID0gIiNmZGFlNjEiLCBmb250ZmFjZSA9IDIpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAyMDIwLjYwLCB5ID0gMjUwLCBsYWJlbCA9ICIyOTUiLCBjb2xvdXIgPSAiI2Q3MTkxYyIsIGZvbnRmYWNlID0gMikgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDIwMjAuNjAsIHkgPSA0NTAsIGxhYmVsID0gIjMzOCIsIGNvbG91ciA9ICIjYWJkZGE0IiwgZm9udGZhY2UgPSAyKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMjAyMC42MCwgeSA9IDUwLCBsYWJlbCA9ICIxMDYiLCBjb2xvdXIgPSAiIzJiODNiYSIsIGZvbnRmYWNlID0gMikgKyAKcG5nKCJ0ZXN0LnBuZyIsIHVuaXRzPSJpbiIsIHdpZHRoPTgsIGhlaWdodD01LCByZXM9MzAwKQojIGluc2VydCBnZ3Bsb3QgY29kZQpkZXYub2ZmKCkKYGBgCgpgYGB7cn0KdWtfZXZfdG9wIDwtIHVrX2V2ICU+JSAKICBtdXRhdGUoYWNyb3NzKGMoeDIwMjFfcTE6eDIwMTFfcTQpLCBhcy5udW1lcmljKSkgJT4lIAogIGZpbHRlcihyZWdpb25fbG9jYWxfYXV0aG9yaXR5X2Fwcl8yMDE5XzMgPT0gIk1pbHRvbiBLZXluZXMiIHwKICAgICAgICAgcmVnaW9uX2xvY2FsX2F1dGhvcml0eV9hcHJfMjAxOV8zID09ICJTd2luZG9uIiB8CiAgICAgICAgIHJlZ2lvbl9sb2NhbF9hdXRob3JpdHlfYXByXzIwMTlfMyA9PSAiU2xvdWdoIiB8IAogICAgICAgICByZWdpb25fbG9jYWxfYXV0aG9yaXR5X2Fwcl8yMDE5XzMgPT0gIkxlZWRzIikgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gYyh4MjAyMV9xMTp4MjAxMV9xNCksIG5hbWVzX3RvID0gYygieWVhciIpLCB2YWx1ZXNfdG8gPSAibm9fb2ZfZXYiKSAlPiUgCiAgZmlsdGVyKHN0cl9kZXRlY3QoeWVhciwgInE0IikpICU+JSAKICBtdXRhdGUoeWVhciA9IHN0cl9zdWIoeWVhciwgMiwgLTQpKQpgYGAKCmBgYHtyfQp1a19ldl90b3AgPC0gdWtfZXZfdG9wICU+JSAKICBsZWZ0X2pvaW4odWtfc2hhcGVfZmlsZSwgYnkgPSBjKCJvbnNfbGFfY29kZV9hcHJfMjAxOSIgPSAibGFkMTljZCIpKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBzdF9hc19zZigpCmBgYAoKYGBge3J9CiMgQ29udmVydGluZyBOTzIgZGlmZiBmcm9tIHggeSB0byBsYXQgbG9uZwpsaWJyYXJ5KHByb2o0KQpwcm9qNHN0cmluZyA8LSAiK3Byb2o9dG1lcmMgK2xhdF8wPTQ5ICtsb25fMD0tMiAraz0wLjk5OTYwMTI3MTcgK3hfMD00MDAwMDAgK3lfMD0tMTAwMDAwICtlbGxwcz1haXJ5ICtkYXR1bT1PU0dCMzYgK3VuaXRzPW0gK25vX2RlZnMiCgpubzJfYWxsX2NsZWFuIDwtIG5vMl9jbGVhbiAlPiUgCiAgcm93aWRfdG9fY29sdW1uKCkKCiMgU291cmNlIGRhdGEKeHkgPC0gbm8yX2FsbF9jbGVhbiAlPiUgCiAgZHBseXI6OnNlbGVjdCh4LCB5LCByb3dpZCkKCiMgVHJhbnNmb3JtZWQgZGF0YQpwaiA8LSBwcm9qZWN0KHh5LCBwcm9qNHN0cmluZywgaW52ZXJzZT1UUlVFKQpsYXRsb24gPC0gZGF0YS5mcmFtZSh4eSwgbGF0PXBqJHksIGxvbj1waiR4KQpubzJfYWxsX2ZpbmFsIDwtICBtZXJnZShubzJfYWxsX2NsZWFuLCBsYXRsb24sIGJ5LnggPSAicm93aWQiLCBieS55ID0gInJvd2lkIikgJT4lCiAgZHBseXI6OnNlbGVjdChsYXQsIGxvbiwgbm8yLCB5ZWFyKSAKYGBgCgpgYGB7cn0KdWtfZXZfdG9wXzIwMjEgPC0gdWtfZXZfdG9wICU+JSAKICBzZWxlY3Qob25zX2xhX2NvZGVfYXByXzIwMTksIHJlZ2lvbl9sb2NhbF9hdXRob3JpdHlfYXByXzIwMTlfMywgeWVhciwgbm9fb2ZfZXYpCgojIGZpbHRlciBmb3IgZGVzaXJlZCBwb2x5Z29uCiNoaWdobGFuZHMgPC0gdWtfZXZfc3RvY2twb3J0ICU+JSAKICMgZmlsdGVyKHJlZ2lvbl9sb2NhbF9hdXRob3JpdHlfYXByXzIwMTlfMyA9PSAiSGlnaGxhbmQiKSAKCiMgc3Rfam9pbiBzZWVtcyBsZXNzIGRpcnR5CmV2X25vMl9hbGxfeWVhcnMgPC0gbm8yX2FsbF9maW5hbCAlPiUgCiAgc3RfYXNfc2YoY29vcmRzID0gYygibG9uIiwgImxhdCIpLCBjcnMgPSBzdF9jcnModWtfZXZfdG9wXzIwMjEpKSAlPiUKICBzdF9qb2luKHVrX2V2X3RvcF8yMDIxLCBqb2luID0gc3RfaW50ZXJzZWN0cywgbGVmdCA9IEZBTFNFKSAKYGBgCgpgYGB7cn0KZXZfbm8yX2FsbF95ZWFyX3RvcCA8LSB0aWJibGUoZXZfbm8yX2FsbF95ZWFycykgJT4lIAogIGZpbHRlcih5ZWFyLnggPT0geWVhci55KSAlPiUgCiAgbXV0YXRlKG5vMiA9IGFzLm51bWVyaWMobm8yKSkgJT4lIAogIGdyb3VwX2J5KHJlZ2lvbl9sb2NhbF9hdXRob3JpdHlfYXByXzIwMTlfMywgeWVhci54KSAlPiUgCiAgbXV0YXRlKG1lYW5fbm8yID0gbWVhbihubzIpKQpgYGAKCmBgYHtyfQpldl9ubzJfYWxsX3llYXJfdG9wICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhci54LCB5ID0gbm9fb2ZfZXYsIGNvbG91ciA9IHJlZ2lvbl9sb2NhbF9hdXRob3JpdHlfYXByXzIwMTlfMykpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygyMDExOjIwMTkpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAyNzUwLCAyNTApKSArCiAgbGFicyh0aXRsZSA9ICJIaWdoIEVWIExvY2FsIEF1dGhvcml0eSBvdmVyIFllYXJzIiwKICAgICAgIHggPSAiWWVhciIsCiAgICAgICB5ID0gIk51bWJlciBvZiBFbGVjdHJpYyBWZWhpY2xlcyIsCiAgICAgICBjb2xvdXIgPSAiTG9jYWwgQXV0aG9yaXR5IikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCgpgYGB7cn0KZXZfbm8yX2FsbF95ZWFyX3RvcCAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fbGluZShhZXMoeCA9IHllYXIueCwgeSA9IG1lYW5fbm8yLCBjb2xvdXIgPSByZWdpb25fbG9jYWxfYXV0aG9yaXR5X2Fwcl8yMDE5XzMpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoMjAxMToyMDE5KSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKDEwOjI4KSkgKwogIGxhYnModGl0bGUgPSAiTWVhbiBOTzIgcGVyIFllYXIgYnkgTG9jYWwgQXV0aG9yaXR5IiwKICAgICAgIHggPSAiWWVhciIsCiAgICAgICB5ID0gIk1lYW4gTk8yIiwKICAgICAgIGNvbG91ciA9ICJMb2NhbCBBdXRob3JpdHkiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKYGBge3J9CmV2X2NoYXJnaW5nX21hcF8yMDIxIDwtIGV2X2NoYXJnaW5nX21hcCAlPiUgCiAgc2VsZWN0KGxhX3JlZ2lvbl9jb2RlLCBsb2NhbF9hdXRob3JpdHlfcmVnaW9uX25hbWUueCwgY291bnRfcmFwaWQsIGNvdW50X3RvdGFsLCBnZW9tZXRyeSkKCiMgc3Rfam9pbiBzZWVtcyBsZXNzIGRpcnR5CmV2X2NoYXJnaW5nX25vMiA8LSBmaW5hbCAlPiUgCiAgc3RfYXNfc2YoY29vcmRzID0gYygibG9uIiwgImxhdCIpLCBjcnMgPSBzdF9jcnMoZXZfY2hhcmdpbmdfbWFwXzIwMjEpKSAlPiUgCiAgc3Rfam9pbihldl9jaGFyZ2luZ19tYXBfMjAyMSwgam9pbiA9IHN0X2ludGVyc2VjdHMsIGxlZnQgPSBGQUxTRSkgJT4lIAogIGdyb3VwX2J5KGxvY2FsX2F1dGhvcml0eV9yZWdpb25fbmFtZS54KSAlPiUgCiAgbXV0YXRlKG1lYW5fbm8yID0gbWVhbihubzIpKQpgYGAKICAKYGBge3J9CmV2X2NoYXJnaW5nX25vMl9sb2cgPC0gZXZfY2hhcmdpbmdfbm8yICU+JSAKICBtdXRhdGUoY291bnRfcmFwaWRfbG9nID0gbG9nKGNvdW50X3JhcGlkKSwKICAgICAgICAgY291bnRfdG90YWxfbG9nID0gbG9nKGNvdW50X3RvdGFsKSwKICAgICAgICAgbWVhbl9ubzJfbG9nID0gbG9nKG1lYW5fbm8yKSkKYGBgCiAgCmBgYHtyfQpldl9jaGFyZ2luZ19ubzIgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IGNvdW50X3JhcGlkLCB5ID0gbWVhbl9ubzIpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKHNlID0gVFJVRSwgbWV0aG9kID0gbG0pCmBgYAoKYGBge3J9CmV2X2NoYXJnaW5nX25vMiAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gY291bnRfdG90YWwsIHkgPSBtZWFuX25vMikgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBUUlVFLCBtZXRob2QgPSBsbSkKYGBgCgpgYGB7cn0KZXZfY2hhcmdpbmdfbm8yX2xvZyAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gY291bnRfcmFwaWRfbG9nLCB5ID0gbWVhbl9ubzJfbG9nKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChzZSA9IFRSVUUsIG1ldGhvZCA9IGxtKQpgYGAKCmBgYHtyfQpldl9jaGFyZ2luZ19ubzJfbG9nICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBjb3VudF90b3RhbF9sb2csIHkgPSBtZWFuX25vMl9sb2cpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKHNlID0gVFJVRSwgbWV0aG9kID0gbG0sIGNvbG91ciA9ICIjMDhhNDRjIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJcbkVWIENoYXJnZXJzIHZzIE1lYW4gTk8yIENvbmMgZm9yIGVhY2ggVUsgTG9jYWwgQXV0aG9yaXR5IGluIDIwMTlcbiIsCiAgICAgICB4ID0gIlxuVG90YWwgTnVtYmVyIG9mIEVWIENoYXJnZXJzIChsb2cpXG4iLAogICAgICAgeSA9ICJcbk1lYW4gTk8yIENvbmMgKGxvZylcbiIpICsKICBwbmcoImV2X2NoYXJnZXJfbm8yX2xvZy5wbmciLCB1bml0cz0iaW4iLCB3aWR0aD04LCBoZWlnaHQ9NSwgcmVzPTMwMCkKYGBgCgpgYGB7cn0KaW5jb21lX2VuZ2xhbmQgPC0gcmVhZF9jc3YoaGVyZSgicmF3X2RhdGEvaW5jb21lZXN0aW1hdGVzZm9yc21hbGxhcmVhc2RhdGFzZXRmaW5hbmNpYWx5ZWFyZW5kaW5nMjAxODEgMi9Ub3RhbCBhbm51YWwgaW5jb21lLVRhYmxlIDEuY3N2IiksIHNraXAgPSA0KSAlPiUgCiAgY2xlYW5fbmFtZXMoKSAlPiUgCiAgc2VsZWN0KGxvY2FsX2F1dGhvcml0eV9jb2RlLCBsb2NhbF9hdXRob3JpdHlfbmFtZSwgdG90YWxfYW5udWFsX2luY29tZSkgJT4lIAogIGdyb3VwX2J5KGxvY2FsX2F1dGhvcml0eV9jb2RlKSAlPiUgCiAgbXV0YXRlKG1lYW5fdG90YWxfYW5udWFsX2luY29tZSA9ICBtZWFuKHRvdGFsX2FubnVhbF9pbmNvbWUpKSAlPiUgCiAgc2VsZWN0KC10b3RhbF9hbm51YWxfaW5jb21lKSAlPiUgCiAgdW5pcXVlKCkKYGBgCgpgYGB7cn0KdWtfZXZfaW5jb21lIDwtIHVrX2V2ICU+JSAKICBpbm5lcl9qb2luKGluY29tZV9lbmdsYW5kLCBieSA9IGMoIm9uc19sYV9jb2RlX2Fwcl8yMDE5IiA9ICJsb2NhbF9hdXRob3JpdHlfY29kZSIpKSAlPiUgCiAgc2VsZWN0KHJlZ2lvbl9sb2NhbF9hdXRob3JpdHlfYXByXzIwMTlfMywgeDIwMjFfcTEsIG1lYW5fdG90YWxfYW5udWFsX2luY29tZSkgJT4lIAogIG11dGF0ZSh4MjAyMV9xMSA9IGFzLm51bWVyaWMoeDIwMjFfcTEpLAogICAgICAgICB4MjAyMV9xMV9sb2cgPSBsb2coeDIwMjFfcTEpKQpgYGAKCmBgYHtyfQp1a19ldl9pbmNvbWUgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IHgyMDIxX3ExX2xvZywgeSA9IG1lYW5fdG90YWxfYW5udWFsX2luY29tZSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0sIGNvbG91ciA9ICIjMDhhNDRjIiwgc2UgPSBGQUxTRSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJcbkVWcyB2cyBNZWFuIEFubnVhbCBJbmNvbWUgZm9yIExvY2FsIEF1dGhvcml0aWVzIGluIEVuZ2xhbmQgYW5kIFdhbGVzXG4iLAogICAgICAgeCA9ICJcbk51bWJlciBvZiBFbGVjdHJpYyBWZWhpY2xlcyAobG9nKVxuIiwKICAgICAgIHkgPSAiXG5NZWFuIFRvdGFsIEFubnVhbCBJbmNvbWVcbiIpICsKICBwbmcoImV2X2luY29tZS5wbmciLCB1bml0cz0iaW4iLCB3aWR0aD04LCBoZWlnaHQ9NSwgcmVzPTMwMCkKYGBgCgo=